ios - Swift:如何仅在代码执行后调用此完成 block ?

标签 ios swift firebase

我无法理解为什么这段代码在将用户附加到类别之前执行完成 block 。

首先,我尝试获取类别。每个类别都有一组用户 ID,这些 ID 会循环以从我的数据库中的单独位置获取用户。

这是 Firebase 数据:

["Category 1": {
title = lifestyle;
users =     (
    ESKYpDMPiHW34,
    HJ8ItJDoExZMQ,
    1WDnoPy4PeQkm
);
}, "Category 2": {
title = fitness;
users =     (
    ESKYpDMPiHW3,
    HJ8ItJDoExZM,
    1WDnoPy4PeQk
);
}, "Category 3": {
title = health;
}]

这是我的代码:

class func fetchFeaturedUsers(completion: @escaping ([UserCategory]) -> Swift.Void) {
    var categories = [UserCategory]()

    let dbRef = Database.database().reference().child("categories")
    dbRef.observeSingleEvent(of: .value, with: { (snap) in

        if let dict = snap.value as? [String: Any] {
            for (_, value) in dict {

                if let category = value as? [String:Any] {

                    let title = category["title"] as? String
                    let newCategory = UserCategory(title: title?.capitalized, users: [User]())
                    categories.append(newCategory)

                    if let users = category["users"] as? [String] {
                        for id in users {
                            User.fetchUser(userId: id, completion: { (newUser) in
                                newCategory.users?.append(newUser)
                            })
                        }
                    }
                }
            }
        }
        DispatchQueue.main.async {
            completion(categories)
        }
    })
}

最佳答案

问题是您的 User.fetchUser 方法是在另一个线程中完成的异步调用。要解决这个问题,您可以创建一个 DispatchGroup,它会等到所有调用完成后再调用 completion,如下所示:

class func fetchFeaturedUsers(completion: @escaping ([UserCategory]) -> Swift.Void) {
    var categories = [UserCategory]()
    let dispatchGroup = DispatchGroup()

    let dbRef = Database.database().reference().child("categories")
    dbRef.observeSingleEvent(of: .value, with: { (snap) in

        if let dict = snap.value as? [String: Any] {
            for (_, value) in dict {

                if let category = value as? [String:Any] {

                    let title = category["title"] as? String
                    let newCategory = UserCategory(title: title?.capitalized, users: [User]())
                    categories.append(newCategory)

                    if let users = category["users"] as? [String] {
                        for id in users {
                            dispatchGroup.enter()
                            User.fetchUser(userId: id, completion: { (newUser) in
                                newCategory.users?.append(newUser)
                                dispatchGroup.leave()
                            })
                        }
                    }
                }
            }
        }

        dispatchGroup.notify(queue: DispatchQueue.global(qos: .background)){
            completion(categories)                
        }
    })
}

您可以在 documentation 中阅读有关 DispatchGroup 的更多信息.

关于ios - Swift:如何仅在代码执行后调用此完成 block ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44731508/

相关文章:

ios - 如何使用 UIBezierPath 绘制一个倾斜的椭圆

ios - SDWebImage-避免在进入背景时清除图像缓存

javascript - Firebase 存储 : string does not match format base64: invalid character found. 仅当调试关闭时

ios - Swift:使用 firebase 时 TableView 的索引超出范围错误

iphone - 推送 View Controller 时无法设置 uiimageview 的图像

ios - 我想使用 swift 从游戏中将我在游戏中获得的分数发布到 Facebook,一切都在 Obj-C 上

ios - 约束问题

swift - 捕获 RealmSwift 写入错误,即删除

ios - Firebase 错误 : You must enable this service in the console

ios - 表格 View 不适用于自定义单元格