首页 > 解决方案 > Swift 和 Firebase:闭包竞争条件

问题描述

我需要在闭包中调用闭包并避免竞争条件。

目前,我有一个名为FirebaseUtilities的类,其中包含与调用 Firebase 和检索数据有关的所有代码。

应用逻辑

一篇文章有​​很多数据,如标题、摘要、正文、主题等。主题使用以下约定链接到文章:

在此处输入图像描述

在这个类中,我有一个获取文章的函数:

获取文章的闭包

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

    var subjects = [Subject]()

    Database.database().reference().child("articles").observe(.value) { (snapshot) in
        // in here i get the value of the snapshot and from there i extract the key of each subject and i store it in an array of String (ex. ["-MD4tN_AjPuCvTUEyZyL"])

        // then I call another closure that is responsible for fetching the subjects based on the UID of each subject (see below)
    }
    
})

获取主题的闭包

func fetchSubjects(subjectsUids: [String], completion: @escaping ([Subject]?, Error?) -> Void) {
    
    var subjects = [Subject]()
    
    subjectsUids.forEach { (subjectUid) in
        self.dbSubjectsRef.child(subjectUid).observe(.value) { (snapshot) in
            guard let subjectDictionary = snapshot.value as? [String: Any] else { return }
            
            let subject = Subject(dictionary: subjectDictionary)
            
            subjects.append(subject)
            
            completion(subjects, nil)
        }
    }
}

问题

Subjects 数组将始终是一个空数组,因为它总是比从 Firebase 获取数据要快:

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

    var subjects = [Subject]()

    Database.database().reference().child("articles").observe(.value) { (snapshot) in
        // in here i get the value of the snapshot and from there i extract the key of each subject and i store it in an array of String (ex. ["-MD4tN_AjPuCvTUEyZyL"])

        // then I call another closure that is responsible for fetching the subjects based on the UID of each subject

        self.fetchSubjects(subjectsUids: subjectsUids) { (subjectsResults, error) in
            guard let sub = subjectsResults else { return }
            subjects = sub
            
            // (A) printing here **shows desired results**
            print(subjects)
         }

         // (B) printing here **does not show the results**
         // it returns an empty array []
         print(subjects)
    }    
})

我想要的是:

我需要在第二个闭包之外获取主题数组(self.fetchSubjects(....))。

关于如何解决这种竞争条件的任何想法?

标签: swiftfirebasefirebase-realtime-databaseclosuresrace-condition

解决方案


我需要在第二个闭包之外获取主题数组(self.fetchSubjects(....))。

这是不可能的:任何需要主题的代码都需要在闭包内,或者从那里调用。

如果你想在其他地方使用主题列表,你可以做你对fetchSubjects函数所做的事情:传入一个回调,然后在加载主题时调用该回调。

另请参阅有关在 Swift 中从 Firebase 异步加载数据的其他问题


推荐阅读