如何在多个闭包中更改变量并使用结果

时间:2018-08-22 14:26:52

标签: swift closures

我要将3个不同的文件上传到AWS S3存储桶。我正在通过返回布尔(Bool)检查每次上传是否成功。如果所有3次上传均成功,则我的代码的另一部分将运行。

我遇到的问题是在一个闭包内更改了uploadSuccessful变量,因此我的其余代码在更新之前就已运行。

我的代码如下:

上传功能-

    func uploadData(fileUrl: URL, key: String, content: String, completion: @escaping(Bool) -> ()) {

    var success = false

    let expression = AWSS3TransferUtilityUploadExpression()
    expression.progressBlock = {(task, progress) in
        DispatchQueue.main.async(execute: {
            // Do something e.g. Update a progress bar.
        })
    }

    let transferUtility = AWSS3TransferUtility.default()

        transferUtility.uploadFile(fileUrl, bucket: "liopa-datacapture-ios", key: key, contentType: content, expression: expression) { (task, error) in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                success = false
                completion(success)
                return
            }

            print("Successfully uploaded")
            success = true
            completion(success)   
      }

}

要上传的文件-

var videoSuccessful = false
var audioSuccessful = false 
var landmarksSuccessful = false 


// upload files to S3 bucket
        // video file
        s3Bucket.uploadData(fileUrl: videoRecorder.outputFileLocation!, key: "ios-videos/\(userName)-\(device)/session-\(sessionNumber)-\(sessionTimestamp)/video-\(phraseNumber)/video-\(phraseNumber).mp4", content: "video") { (success) in
            DispatchQueue.main.async {
                videoSuccessful = success
            }
        }
        // audio file
        s3Bucket.uploadData(fileUrl: audioRecorder.outputAudioLocation, key: "ios-videos/\(userName)-\(device)/session-\(sessionNumber)-\(sessionTimestamp)/video-\(phraseNumber)/audio-\(phraseNumber).flac", content: "audio") { (success) in
            DispatchQueue.main.async {
                audioSuccessful = success
            }
        }
        //facial landmark coordinates
        s3Bucket.uploadData(fileUrl: createFacialLandmarksFile(), key: "ios-videos/\(userName)-\(device)/session-\(sessionNumber)-\(sessionTimestamp)/video-\(phraseNumber)/metadata/Phrase\(phraseNumber)-landmarks.txt", content: "text") { (success) in
            DispatchQueue.main.async {
                landmarksSuccessful = success
            }
        }

        print(uploadSuccessful)

        if videoSuccessful && audioSuccessful && landmarksSuccessful  { // continue on

我知道我可能完全以错误的方式进行此操作。但是,如何立即更改uploadSuccessful Bool,然后在代码末尾的if语句中使用它的值?

1 个答案:

答案 0 :(得分:1)

您缺少几点:

您的上传是异步的。意味着您应该先print(uploadSuccessful)到达uploadSuccessful = success
要等待所有异步调用结束,然后再执行其他操作,请使用DispatchGroup
即使这样,您也可能会遇到问题,因为如果两个失败但不是最后一个失败,那么您将拥有uploadSuccessful == true
您可以使用let allRequestSucceed = true 在每个请求结束时,仅在allRequestSucceed时更新success == false,但计数器也是一种好方法。

let group = DispatchGroup()
let successFullRequestCounter: Int = 0

//First upload
group.enter()
s3Bucket.uploadData(fileUrl: ...) { (success) in
    if success { 
        successFullRequestCounter = successFullRequestCounter + 1
    }
    group.leave()
}

//Second upload
group.enter()
s3Bucket.uploadData(fileUrl: ...) { (success) in
    if success { 
        successFullRequestCounter = successFullRequestCounter + 1
    }
    group.leave()
}

//Third upload
group.enter()
s3Bucket.uploadData(fileUrl: ...) { (success) in
    if success { 
        successFullRequestCounter = successFullRequestCounter + 1
    }
    group.leave()
}

//Because of the enter()/leave(), this code will executes only when 3 uploaded ended
group.notify(queue: DispatchQueue.main) {
    if successFullRequestCounter == 3 { 
        //All request did succeed
    }
    successFullRequestCounter = 0 //Reset the value if it's a instance var
}