我有一个包含帖子ID的数组,然后我执行一个for
循环并检索每个帖子内容并将帖子附加到帖子数组中。循环结束后,我需要在完成处理程序中返回 post 数组。
但是,.observeSingleEvent 是一个异步方法,因此帖子内容是从 Firebase 检索的,completionhandler(posts( 已经执行,它返回一个空数组。我想在将每个帖子附加到数组后返回数组,类似于使这些方法同步。
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)
}
可以使用DispatchGroup
在一系列任务完成时执行一些代码。
在启动任务之前调用 enter
函数,在任务完成后调用 leave
函数。 您可以使用notify
提供一个闭包,一旦所有任务都"离开"了DispatchGroup
,就会执行该闭包。
您还需要小心避免更新数组时出现并发问题;Swift 数组不是线程安全的。 在串行调度队列上执行阵列更新可以解决此问题。
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)
}
}