swift - 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(....))。
关于如何解决这种竞争条件的任何想法?
解决方案
我需要在第二个闭包之外获取主题数组(self.fetchSubjects(....))。
这是不可能的:任何需要主题的代码都需要在闭包内,或者从那里调用。
如果你想在其他地方使用主题列表,你可以做你对fetchSubjects
函数所做的事情:传入一个回调,然后在加载主题时调用该回调。
另请参阅有关在 Swift 中从 Firebase 异步加载数据的其他问题。
推荐阅读
- testing - 如何在不影响 UI 交付质量的情况下减少测试金字塔中的 UI 测试
- arrays - Form1 列表框在第二次打开时未加载到 form3 数组
- php - JWPlayer 使用 php 文件而不是直接链接不起作用
- android - Crashlytics 无法初始化
- javascript - 制作一个将数字放在数组中间的函数
- css - 我正在尝试使用一个很棒的字体图标作为按钮
- sql - 如何在 Oracle SQL 输出中将行转换为表列?
- spring-boot - 我在 Jpql 中使用 @Query 注释,我用额外的“不同”修改了我的查询,如何修复它?
- algorithm - 以最高效率访问无向图中所有节点的算法?
- python - '没有这样的文件或目录' 使用“打印”时的错误信息