ios - 从 iOS 上传多张图片到 S3 的有效方法

标签 ios amazon-web-services amazon-s3

我在应用程序中使用 Amazon S3 作为我的文件存储系统。我所有的项目对象都有几个与之关联的图像,每个图像只存储图像 url 以保持我的数据库轻量级。因此,我需要一种直接从 iOS 将多个图像上传到 S3 的有效方法,并在成功完成后将它们的 url 存储在我发送到服务器的对象中。我仔细阅读了亚马逊提供的 SDK 和示例应用程序,但我遇到的唯一示例是单个图像上传,如下所示:

 func uploadData(data: NSData) {
    let expression = AWSS3TransferUtilityUploadExpression()
    expression.progressBlock = progressBlock

    let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility()

    transferUtility.uploadData(
        data,
        bucket: S3BucketName,
        key: S3UploadKeyName,
        contentType: "text/plain",
        expression: expression,
        completionHander: completionHandler).continueWithBlock { (task) -> AnyObject! in
            if let error = task.error {
                NSLog("Error: %@",error.localizedDescription);
                self.statusLabel.text = "Failed"
            }
            if let exception = task.exception {
                NSLog("Exception: %@",exception.description);
                self.statusLabel.text = "Failed"
            }
            if let _ = task.result {
                self.statusLabel.text = "Generating Upload File"
                NSLog("Upload Starting!")
                // Do something with uploadTask.
            }

            return nil;
    }
}

对于 5 张以上的图像,这将变成一个嵌套的困惑,因为我必须等待每次上传成功返回,然后才能启动下一个,然后最终将对象发送到我的数据库。是否有一种高效、代码整洁的方法可以帮助我实现我的目标?

Amazon 示例应用程序 github 的 URL:https://github.com/awslabs/aws-sdk-ios-samples/tree/master/S3TransferUtility-Sample/Swift

最佳答案

这是我使用 DispatchGroup() 同时将多张图片上传到 S3 的代码。

func uploadOfferImagesToS3() {
    let group = DispatchGroup()

    for (index, image) in arrOfImages.enumerated() {
        group.enter()

        Utils.saveImageToTemporaryDirectory(image: image, completionHandler: { (url, imgScalled) in
            if let urlImagePath = url,
                let uploadRequest = AWSS3TransferManagerUploadRequest() {
                uploadRequest.body          = urlImagePath
                uploadRequest.key           = ProcessInfo.processInfo.globallyUniqueString + "." + "png"
                uploadRequest.bucket        = Constants.AWS_S3.Image
                uploadRequest.contentType   = "image/" + "png"
                uploadRequest.uploadProgress = {(bytesSent:Int64, totalBytesSent:Int64, totalBytesExpectedToSend:Int64) in
                    let uploadProgress = Float(Double(totalBytesSent)/Double(totalBytesExpectedToSend))

                    print("uploading image \(index) of \(arrOfImages.count) = \(uploadProgress)")

                    //self.delegate?.amazonManager_uploadWithProgress(fProgress: uploadProgress)
                }

                self.uploadImageStatus      = .inProgress

                AWSS3TransferManager.default()
                    .upload(uploadRequest)
                    .continueWith(executor: AWSExecutor.immediate(), block: { (task) -> Any? in

                        group.leave()

                        if let error = task.error {
                            print("\n\n=======================================")
                            print("❌ Upload image failed with error: (\(error.localizedDescription))")
                            print("=======================================\n\n")

                            self.uploadImageStatus = .failed
                            self.delegate?.amazonManager_uploadWithFail()

                            return nil
                        }

                        //=>    Task completed successfully
                        let imgS3URL = Constants.AWS_S3.BucketPath + Constants.AWS_S3.Image + "/" + uploadRequest.key!
                        print("imgS3url = \(imgS3URL)")
                        NewOfferManager.shared.arrUrlsImagesNewOffer.append(imgS3URL)

                        self.uploadImageStatus = .completed
                        self.delegate?.amazonManager_uploadWithSuccess(strS3ObjUrl: imgS3URL, imgSelected: imgScalled)

                        return nil
                    })
            }
            else {
                print(" Unable to save image to NSTemporaryDirectory")
            }
        })
    }

    group.notify(queue: DispatchQueue.global(qos: .background)) {
        print("All \(arrOfImages.count) network reqeusts completed")
    }
}

这是关键部分,我至少浪费了 5 个小时。 来自 NSTemporaryDirectory 的 URL 对于每张图片必须不同!!!

class func saveImageToTemporaryDirectory(image: UIImage, completionHandler: @escaping (_ url: URL?, _ imgScalled: UIImage) -> Void) {
    let imgScalled              = ClaimitUtils.scaleImageDown(image)
    let data                    = UIImagePNGRepresentation(imgScalled)

    let randomPath = "offerImage" + String.random(ofLength: 5)

    let urlImgOfferDir = URL(fileURLWithPath: NSTemporaryDirectory().appending(randomPath))
    do {
        try data?.write(to: urlImgOfferDir)
        completionHandler(urlImgOfferDir, imgScalled)
    }
    catch (let error) {
        print(error)
        completionHandler(nil, imgScalled)
    }
}

希望这会有所帮助!

关于ios - 从 iOS 上传多张图片到 S3 的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41705839/

相关文章:

amazon-web-services - 如何使用 Hostinger 域验证 AWS 证书?

javascript - s3 javascript 创建存储桶

swift - Xcode - 无法打开,因为不支持 URL 类型 http

ios14 Xcode 12 - 触摸 SwiftUI 对象时 Sprite 不显示,但触摸 SKScene 时可以工作

ios - 按 UITextView 上的链接时应用程序崩溃

ios - 如何在 ViewController 之后启动 TabBarController

amazon-web-services - 通过 amazon api 获取和发送消息

linux - Elastic Beanstalk 上的 PostgreSQL (Amazon Linux 2)

amazon-s3 - 尼菲 : Delete files from S3 when they are X days old

iphone - 设置在 Interface Builder 中通过代码创建的 UIButton 图像