为什么此完成处理程序跳过for循环 [英] Why is this completion handler skipping a for loop
问题描述
我有这组代码,我只想运行:self.performSegue
在所有的for循环和Firebase的所有异步任务都已完成运行之后:
I have this group of code, I only want to run: self.performSegue
AFTER all of the for loops and all of the Firebase's asynchronous tasks have finished running:
getFeaturedPost(withCompletion: startNext)
func getFeaturedPost(withCompletion completion: () -> Void ) {
print("Getting featured posts...")
ref.child("featured").child("amount").observeSingleEvent(of: .value, with: { (snapshot) in
self.numberOfPosts = snapshot.value as! Int
print("There's \(self.numberOfPosts) posts avaliable.")
for pos in 0..<self.numberOfPosts{
print("Getting reference names for post: \(pos + 1)")
self.ref.child("featured").child("post\(pos + 1)").observeSingleEvent(of: .value, with: { (snapshot) in
let postID = (snapshot.value as? NSDictionary)?["postID"] as? String ?? ""
let userOfPost = (snapshot.value as? NSDictionary)?["userOfPost"] as? String ?? ""
self.customValues.append(("/users/public/\(userOfPost)/posts/\(postID)"))
})
}
})
print("Done! The posts are: \(customValues)")
completion()
}
func startNext()
{
getPostData(withCompletion: {
print("Finished getting data, going to main screen.")
self.performSegue(withIdentifier: "showHome", sender: nil)
})
}
func getPostData(withCompletion completion: () -> Void ) {
print("Getting idividual post data, there are \(customValues.count) posts")
for i in 0..<customValues.count {
print("Currently on post: \(i)")
let encodedURL = (customValues[i] + "/postURL")
ref.child(encodedURL).observe(.value, with: { (snapshot) in
if let newURL = snapshot.value as? String{
print("Sending \(newURL) to DemoSource Class")
DemoSource.shared.add(urlString: newURL)
}
})
}
completion()
}
但是startNext()
函数(转到下一个视图)在getFeaturedPost
开始之前执行,它是for循环,在其中打印当前位置.最终,当我使用DemoSource.shared.add(urlString: newURL)
将数据发送到demosource类时,newURL
为nil时,我有了一个控制台日志,该日志显示了每个函数的打印语句的顺序:
Yet the startNext()
function (which goes to the next view) is executed before getFeaturedPost
's starts it's for loop where it prints what post it'c currently at. By the end when I send the data to the demosource class with DemoSource.shared.add(urlString: newURL)
the newURL
is nil, I have a console log which shows you the order of the print statements of each function:
Getting featured posts...
Done! The posts are: []
Getting idividual post data, there are 0 posts
Finished getting data, going to main screen. // This line should be printed last meaning this function is being executed too early
There's 2 posts avaliable.
Getting reference names for post: 1 // These two lines should be called before the line 'Finished getting data'
Getting reference names for post: 2
推荐答案
DispatchGroup
的用法非常简单.这是一种柜台. enter
递增计数器,leave
递减计数器.如果计数器达到0
,则会执行notify
中的关闭操作.
The usage of DispatchGroup
is very easy. It's a kind of a counter. enter
increments the counter, leave
decrements it. If the counter reaches 0
the closure in notify
is executed.
- 在异步块调用
enter
之前的循环中. - 在结束调用
leave
的异步块内部. -
循环调用
notify
之后.
- In the loop before the asynchronous block call
enter
. - Inside the asynchronous block at the end call
leave
. After the loop call
notify
.
func getFeaturedPost(withCompletion completion: @escaping () -> Void ) {
print("Getting featured posts...")
ref.child("featured").child("amount").observeSingleEvent(of: .value, with: { (snapshot) in
self.numberOfPosts = snapshot.value as! Int
print("There's \(self.numberOfPosts) posts avaliable.")
let group = DispatchGroup()
for pos in 0..<self.numberOfPosts{
group.enter()
print("Getting reference names for post: \(pos + 1)")
self.ref.child("featured").child("post\(pos + 1)").observeSingleEvent(of: .value, with: { (snapshot) in
if let post = snapshot.value as? [String:Any] {
let postID = post["postID"] as? String ?? ""
let userOfPost = post["userOfPost"] as? String ?? ""
self.customValues.append(("/users/public/\(userOfPost)/posts/\(postID)"))
}
group.leave()
})
}
group.notify(queue: .main) {
print("Done! The posts are: \(customValues)")
completion()
}
})
}
使用另一种方法相应地实施组.
Implement a group accordingly in the other method.
旁注:不要在Swift中使用NS...
集合类型.
Side note: Don't use NS...
collection types in Swift.
这篇关于为什么此完成处理程序跳过for循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!