【问题标题】:Completion handler called before data loads在数据加载之前调用的完成处理程序
【发布时间】:2018-01-21 10:16:30
【问题描述】:

如何防止在以下代码中从 firebase 加载数据之前调用完成处理程序?

我的问题: 在将任何用户附加到用户数组之前调用完成。只有在users 实际附加了用户之后,我如何才能调用completion

我必须使用 Grand Central Dispatch 吗?

如果您能像我 5 岁一样向我解释这一点,则可以加分。老了,所以我可以停止面对这个问题。

class func fetchFavorites(userId: String, completion: @escaping ([User]) -> Swift.Void) {
    let userRef = Database.database().reference().child("users")
    let favRef = Database.database().reference().child("favorites").child(userId)

    favRef.observe(.value) { snap in
        var users: [User] = []
        for item in snap.children.allObjects as! [DataSnapshot] {
            userRef.child(item.key).observeSingleEvent(of: .value) { snapshot in
                if let dictionary = snapshot.value as? [String:Any] {
                    let newUser = User(dictionary: dictionary)
                    users.append(newUser)
                }
            }
        }
        completion(users)
    }
}

【问题讨论】:

  • 您的completion() 以异步方式在favRef.observe(.value){} 上被调用,没关系,但userRef.child(item.key).observeSingleEvent(of: .value){} 也是异步的,这是您的问题。
  • 感谢您的回复,但我不确定我是否关注。你能在代码中澄清一下吗?

标签: swift firebase-realtime-database grand-central-dispatch


【解决方案1】:

您有两个嵌套的异步函数,即favRef.observeuserRef.child().observeSingleEvent(of:),因此问题是completion 在更新用户的所有异步调用完成执行之前在外部闭包中被调用。

您可以通过使用DispatchGroup 并仅在所有异步方法调用完成循环中的执行后才调用completion 来解决此问题。这可以通过将所有异步调用添加到DispatchGroup,然后在group.notify 调用中调用completion 来实现。

class func fetchFavorites(userId: String, completion: @escaping ([User]) -> Swift.Void) {
    let userRef = Database.database().reference().child("users")
    let favRef = Database.database().reference().child("favorites").child(userId)
    let usersGroup = DispatchGroup()

    favRef.observe(.value) { snap in
        var users: [User] = []
        for item in snap.children.allObjects as! [DataSnapshot] {
            usersGroup.enter()
            userRef.child(item.key).observeSingleEvent(of: .value) { snapshot in
                if let dictionary = snapshot.value as? [String:Any] {
                    let newUser = User(dictionary: dictionary)
                    users.append(newUser)
                }
                usersGroup.leave()
            }
        }
        usersGroup.notify(queue: DispatchQueue.global()){
            completion(users)
        }
    }
}

【讨论】:

    猜你喜欢
    • 2012-02-13
    • 1970-01-01
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多