为什么此完成处理程序跳过for循环 [英] Why is this completion handler skipping a for loop

查看:58
本文介绍了为什么此完成处理程序跳过for循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这组代码,我只想运行: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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆