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

时间:2017-03-23 05:33:38

标签: ios multithreading swift3 vk

我正在使用SwiftyVK和SwiftyJSON框架创建一个社交网络应用程序。有一个功能发送附有照片的帖子。我们称之为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)")}
        )
}

所以确切的问题是,在循环内部,上传任务被分派到另一个线程,并且服务器的响应分别在另一个时间到达其他地方。事实上,到目前为止我需要附件字符串填充 photoString (在调用VK.API.Wall.post()之前),实际上有表格,例如“photo123456_,photo123456_,photo123456_”,即没有带照片的身份证,因为这些照片尚未在其他帖子中上传,因此这些ID未添加到附件

问题是,如何在Swift中实现在循环的每次迭代中我们都没有继续但等到照片上传后,将其id添加到 photoString 以收集这些< 附件中的strong> photoString ,所以在调用VK.API.Wall.post()之前一切都准备好了吗?

2 个答案:

答案 0 :(得分:0)

这样的事情可以适用于您的情况

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))") }
       )

    }


}

答案 1 :(得分:0)

我在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()
        }
    }