使用 Swift 闭包和 Firebase 处理异步数据

Working with asynchronous data with Swift closures and Firebase

我需要调用特定的 Firebase 引用并取回数据。此操作将在多个 VC 内进行,因此我希望有一个 class,我将在其中调用 Firebase 的各种函数。例如,如果我想获取所有文章,我将调用我的 FirebaseHelpers class,并使用 method/closure fetchArticles()。这样,如果我想重构某些东西,我只会在 FirebaseHelpers class 中进行,而不会遍历所有 VCs.

FirebaseHelpers

import UIKit
import Firebase

class FirebaseHelpers {

    func fetchArticles(completion: @escaping ([Article]?, Error?) -> Void) {
            
        var articles = [Article]()

        let articlesQuery = Database.database().reference().child("articles").queryOrdered(byChild: "createdAt")

        articlesQuery.observe(.value, with: { (snapshot) in

            guard let articlesDictionaries = snapshot.value as? [String : Any] else { return }
        
            articlesDictionaries.forEach({ (key, value) in
            
                guard let articleDictionary = value as? [String: Any] else { return }

                // build articles array
                let article = Article(dictionary: articleDictionary)

                print("this is article within closure \(article)")
            
                articles.append(article)
            
            })
        
        })

        completion(articles, nil)
    }
}

任意viewController

let firebaseHelpers = FirebaseHelpers()

var articles = [Article]() {
    didSet {
        self.collectionView.reloadData()
    }
}

// this is inside viewDidLoad()
firebaseHelpers.fetchArticles { (articles, error) in
        
    guard let articles = articles else { return }
        
    print("articles \(articles)")
        
    self.articles = articles
}

问题是我没有得到任何结果。在我的 VC 中,print("articles(articles)") 将 return 一个 空数组 。但是在我的 FirebaseHelpers fetchArticles() 中, print("this is article within closure (article)") 将打印文章 就好了 .

知道为什么会这样吗?

提前致谢。

您可以在异步函数中移动 completion

class FirebaseHelpers {

    func fetchArticles(completion: @escaping ([Article]?, Error?) -> Void) {
            
        var articles = [Article]()

        let articlesQuery = Database.database().reference().child("articles").queryOrdered(byChild: "createdAt")

        articlesQuery.observe(.value, with: { (snapshot) in

            guard let articlesDictionaries = snapshot.value as? [String : Any] else { return }
        
            articlesDictionaries.forEach({ (key, value) in
            
                guard let articleDictionary = value as? [String: Any] else { return }

                // build articles array
                let article = Article(dictionary: articleDictionary)

                print("this is article within closure \(article)")
            
                articles.append(article)
            })
        
            completion(articles, nil) // <- move here
        })

        // completion(articles, nil) // <- remove
    }
}

否则 completion 将在您的异步函数之前被调用。