【问题标题】:Ensuring Async Action Has Completed in Firebase确保 Firebase 中的异步操作已完成
【发布时间】:2016-09-06 03:39:57
【问题描述】:

我需要快速对 Firebase 运行并发查询。如何确保循环查询在允许在我的应用中启动另一个操作之前完成?

例如,第一个查询很简单,只是提取数据。但第二个,遍历一个数组,在我的 firebase 数据库中寻找某个节点,循环遍历数组 self.contacts

 // First check if friend, and remove/add to
            friendsURL.observeSingleEventOfType(.Value, withBlock: { snapshot in

                for oneSnapshot in snapshot.children {

                    for oneContact in contactsArray {

                        for oneContactPhoneNum in oneContact.phoneNumbers {

                            let phoneNumber = oneContactPhoneNum.value as! CNPhoneNumber

                            contactNumber = phoneNumber.stringValue

                            // Clean the number
                            let stringArray = contactNumber!.componentsSeparatedByCharactersInSet(
                                NSCharacterSet.decimalDigitCharacterSet().invertedSet)
                            let newString = "1" + stringArray.joinWithSeparator("")

                            let firebaseFriendNumber = oneSnapshot.value["phoneNumber"] as! String

                            if newString == firebaseFriendNumber {

                                self.friends.append(Friend(userName: oneSnapshot.value["userName"] as! String,phoneNumber: firebaseFriendNumber, status: 2, name: oneContact.givenName, userID: oneSnapshot.key))

                                // Remove that contact
                                self.contacts.removeObject(oneContact)
                            }
                        }
                    }
                }

                // Now do the users search:
                for oneContact in self.contacts {
                    for oneContactNumer in oneContact.phoneNumbers {

                        let phoneNumber = oneContactNumer.value as! CNPhoneNumber

                        contactNumber = phoneNumber.stringValue

                        let stringArray = contactNumber!.componentsSeparatedByCharactersInSet(
                            NSCharacterSet.decimalDigitCharacterSet().invertedSet)
                        let newString = "1" + stringArray.joinWithSeparator("")

                        let usersURL: Firebase! = Firebase(url: firebaseMainURL + "presentUserIDUserNameByPhoneNumber/" + newString)

                        // Check db:

                        usersURL.observeSingleEventOfType(.Value, withBlock: { snapshot in

                            if snapshot.childrenCount > 1 {

                                // They are users (but not your friends):
                                self.friends.append(Friend(userName: snapshot.value["userName"] as! String, phoneNumber: snapshot.key, status: 1, name: "test", userID: snapshot.value["userID"] as! String))

                                let userName = snapshot.value["userName"] as! String

                                print("Friends name: " + userName)

                                // Remove that contact
                                self.contacts.removeObject(oneContact)

                            }

                        })

                    }

                }

            })

如何测试和检查 usersURL 上的第二个何时完成,然后才允许在应用中发生其他操作?

【问题讨论】:

  • 一旦块中的代码开始执行,usersURL 观察就“完成”了。即当“if snapshot.children”触发时,这意味着所有数据都已从 Firebase 中检索到。因此,在该块内执行您需要做的任何事情,然后让最后一行调用应该发生的下一件事 - 显示窗口或更新 tableView 等。是否有理由不能将该块用作“测试” ?

标签: ios swift asynchronous firebase


【解决方案1】:

发出异步函数完成信号的一种方法是使用完成处理程序。您已经在 Firebase API 中使用了完成处理程序,并且系统框架中有许多 API,因此我不再进一步解释。

鉴于这种方法,将您的代码包装到一个函数中,例如带有完成处理程序的updateContacts。通常异步函数会返回计算出的 valueerror。在某些情况下,它只是成功或失败 - 没有返回值。您在完成处理程序的签名中表达了这一点。您的函数updateContacts 可能不会计算值,但无论如何它可能会失败或成功。然后,您可以使用可选错误:如果是nil,则任务成功,否则包含发生的错误。

当您的基础任务完成后,调用完成处理程序并返回结果。

注意:必须确保完成处理程序最终会被调用

func updateContacts(completion: (ErrorType?)-> ()) {
    friendsURL.observeSingleEventOfType(.Value, withBlock: { snapshot in
        ...
            ...
                ...
                    usersURL.observeSingleEventOfType(.Value, withBlock: { snapshot in
                        ...
                        let error = // nil or an error
                        completion(error)
                       return
                     }
        completion(nil)
    }    
}

现在,当您有一个异步子任务数组时,它将被并行调用,并且您希望在所有子任务完成后发出updateContacts 的完成信号 - 您可以利用调度组:

let group = dispatch_group_create()
var error: ErrorType?
contactNumbers.forEach { number in
    dispatch_group_enter(group)
    queryAsync(number) { (result, error) in
        if let error = error {
            // handle error
        } else {
            ...
        }             
        dispatch_group_leave(group)
    }
}
dispatch_group_notify(group, queue) {
    // call the completion handler of your function `updateContacts`:
    completion(error)
}

【讨论】:

  • 问题:如果我将整个contactNumbers.forEach { number in 设置在dispatch_group_enter(group)dispatch_group_leave(group) 中会怎样(这就是我正在做的,但它并没有等待完成所有操作)
  • @Sauron 它会调用..._enter 然后启动N 异步函数,然后立即调用..._leave。如果您随后使用闭包调用..._notify,则将立即(在队列上)调用此闭包,因为该组为空。但N 异步函数仍将运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多