Swift:如何从异步操作中return一个值?

Swift: How to return a value from asynchronous operation?

我正在使用 SwiftyVK 和 SwiftyJSON 框架创建一个社交网络应用程序。有一个功能可以发送 post 和附加的照片。我们称它为 sendToVK()。以下是对其的简要回顾:

func sendToVK(message: String, photos: [UIImage]) {
    // declaration of some vars and lets
    var attachments = "" // this var should collect all the information about 
//photos to attach, for example: "photo123456_987654,photo123456_612366,photo123456_123156",
// where 123456 is id of the user, whose wall I'm going post to (I already have it),
// numbers after "_" are id of the photo, they are contained in the server's response
// in case of successful upload

    for photo in photos {
       // I'm uploading photos in this loop, and I assume that I have to get 
       //the ID's of my photos from server's response also somewhere in this loop in order to work with them further
       //Let's say photoString is someString + photoID, for example, photoString == "photo12345_9876543"
       var photoID = ""
       //the following function is uploading photos asynchronously. 
       //It is also responsible for getting IDs from server's response
       VK.API.Upload.Photo.toWall.toUser(media, userId: userIDForVK).send(
       onSuccess: { response in
         print("\n SwiftyVK: uploadPhoto success \n \(response)")
         photoID = response[0,"id"].stringValue }, //this is SwiftyJSON syntax
       onError: { error in
         print("\n SwiftyVK: uploadPhoto fail \n \(error)") },
       onProgress: { done, total in
         print("\n SwiftyVK: uploadPhoto progress: \(done) of \(total))") }
       )
       photoString = something + photoID //by this moment photoID is empty, that's the problem! (see explanation below)
       attachments += photoString
    }

    //At this moment I must have all the neccessary parameters
    //in the var wallPostParameters, including attachments!
    VK.API.Wall.post(wallPostParameters).send(
            onSuccess: {response in print(response)},
            onError: {error in print(error)},
            onProgress: {done, total in print(" !!!!!!!!!!!!!!! send \(done) of \(total)")}
        )
}

所以确切的问题是,在循环内,上传任务被分派到另一个线程,服务器的响应分别在另一个时间到达其他地方。事实上,现在我需要用 photoStrings 填充 attachments 字符串(就在调用 VK.API.Wall.post( )),其实是这样的形式,比如"photo123456_,photo123456_,photo123456_",即没有照片ID,因为这些照片还没有上传到另一个线程,所以这些ID没有添加到附件.

问题是,我如何在 Swift 中实现在循环的每次迭代中我们不继续而是等待照片上传,将其 id 添加到 photoString 将这些 photoString 收集到 attachments 中,因此在调用 VK.API.Wall.post() 之前一切都准备就绪去吗?

类似这样的方法适用于您的情况

func sendToVK(message: String, photos: [UIImage]) {

    var attachments = "" 
    var photosUploaded = 0

    for photo in photos {


       var photoID = ""
       VK.API.Upload.Photo.toWall.toUser(media, userId: userIDForVK).send(
       onSuccess: { response in
    photosUploaded += 1
         photoID = response[0,"id"].stringValue
photoString = something + photoID 
        attachments += photoString

if photosUploaded == photos.count {

    VK.API.Wall.post(wallPostParameters).send(
            onSuccess: {response in print(response)},
            onError: {error in print(error)},
            onProgress: {done, total in print(" !!!!!!!!!!!!!!! send \(done) of \(total)")}
        )
} 

    }, //this is SwiftyJSON syntax
       onError: { error in
         print("\n SwiftyVK: uploadPhoto fail \n \(error)") },
       onProgress: { done, total in
         print("\n SwiftyVK: uploadPhoto progress: \(done) of \(total))") }
       )

    }


}

我在Swift看过一篇关于GCD的文章,我最后的解决办法是:

private static func sendToVK(_ message: String, photos: [UIImage], userIDForVK: String) {
        var wallPostParameters = Dictionary<VK.Arg, String>()
        wallPostParameters[VK.Arg.message] = message
        var attachments = ""
        var successfulUploadsCount = 0

        let sendPostWorkItem = DispatchWorkItem {
            VK.API.Wall.post(wallPostParameters).send(
            onSuccess: {response in print(response)},
            onError: {error in print(error)},
            onProgress: {done, total in print("\n send \(done) of \(total)\n")} )
        }

        for photo in photos {
            let media = Media(imageData: Data(UIImageJPEGRepresentation(photo, 1.0)!), type: Media.ImageType.JPG)

            VK.API.Upload.Photo.toWall.toUser(media, userId: userIDForVK).send(

                onSuccess: { response in
                    let photoID = response[0,"id"].stringValue
                    let photoString = "photo" + userIDForVK + "_" + photoID

                    if attachments.isEmpty {
                        attachments = photoString
                    } else {
                        attachments += "," + photoString
                    }
                    successfulUploadsCount += 1

                    if successfulUploadsCount == photos.count {
                        wallPostParameters[VK.Arg.attachments] = attachments
                        sendPostWorkItem.perform()
                    }
                    print("\n SwiftyVK: uploadPhoto success \n \(response)\n") },

                onError: { error in
                    print("\n SwiftyVK: uploadPhoto fail \n \(error)\n") },

                onProgress: { done, total in
                    print("\n SwiftyVK: uploadPhoto progress: \(done) of \(total))\n") } )
        }

        if photos.isEmpty {
            sendPostWorkItem.perform()
        }
    }