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)
}
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 theleave
function once the task is complete. You can usenotify
to provide a closure that will be executed once all tasks have 'left' theDispatchGroup
.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.