How do you run code after an async call finishes and the code is outside of the asyn function in swift3

不羁岁月 提交于 2019-12-25 14:48:52

问题


I have an array containing post IDs, then I do a for loop and retrieve each post content and append the post to the post array. After the loop ends, I need to return the post array in the completion handler.

However, the .observeSingleEvent is an async method, therefore the posts contents are retrieve from Firebase, the completionhandler(posts) is already executed, which returns an empty array. I want to return the array after every post is appended to the array, similar to making these methods synchronous.

static func getPost(postKeys:[String], completionHandler: @escaping ([Post])->()){
    var posts = [Post]()
    for postKey in postKeys{
        let postRef = DataService.ds.REF_POSTS.child(postKey)
        postRef.observeSingleEvent(of: .value, with: { (snapshot) in
            if let postDict = snapshot.value as? Dictionary<String, Any>{
                //create a post and append it to the post array
                let key = snapshot.key
                let post = Post(postKey: key, postData: postDict)
                posts.append(post)
            }
        })
    }
    completionHandler(posts)
}

回答1:


You can use a DispatchGroup to execute some code when a series of tasks is complete.

Call the enter function before you start a task and the leave function once the task is complete. You can use notify to provide a closure that will be executed once all tasks have 'left' the DispatchGroup.

You also need to be careful to avoid concurrency issues with updating the array; Swift arrays are not thread-safe. Executing the array update on a serial dispatch queue can fix this.

static func getPost(postKeys:[String], completionHandler: @escaping ([Post])->()){
    var posts = [Post]()
    let dispatchGroup = DispatchGroup()
    let arrayQueue = DispatchQueue(label: "arrayQueue")
    for postKey in postKeys{
        dispatchGroup.enter()
        let postRef = DataService.ds.REF_POSTS.child(postKey)
        postRef.observeSingleEvent(of: .value, with: { (snapshot) in
            if let postDict = snapshot.value as? Dictionary<String, Any>{
                //create a post and append it to the post array
                let key = snapshot.key
                let post = Post(postKey: key, postData: postDict)
                arrayQueue.sync {
                    posts.append(post)
                }
            }
            dispatchGroup.leave()
        })
    }

    dispatchGroup.notify(queue: DispatchQueue.main) { 
        completionHandler(posts)
    }
}


来源:https://stackoverflow.com/questions/43334899/how-do-you-run-code-after-an-async-call-finishes-and-the-code-is-outside-of-the

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!