我需要在swift中对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
上的第二个已完成的时间?
答案 0 :(得分:4)
一种异步函数信号完成的方法是使用完成处理程序。您已经在Firebase API中使用了完成处理程序,系统框架中有许多API,所以我没有进一步解释。
考虑到这种方法,将代码包装到一个函数中,比如说updateContacts
带有一个完成处理程序。通常,异步函数返回计算的值或错误。在某些情况下,它只是成功或失败 - 没有返回值。您在完成处理程序的签名中表达了这一点。您的函数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)
}