我dispatch_group用来调用Firebase请求函数,并在请求完成后得到通知,以便能够处理结果。在这种情况下,我只是打印了一条语句。
dispatch_group
func loadStuff() { dispatch_group_enter(group) myFirebaseFunction() { dispatch_group_leave(group) } dispatch_group_notify(group, dispatch_get_main_queue()) { print("done") } } func myFirebaseFunction(completionHandler: () -> ()) { let usersRef = firebase.child("likes") usersRef.observeEventType(.Value, withBlock: { snapshot in if snapshot.exists() { let sorted = (snapshot.value!.allValues as NSArray).sortedArrayUsingDescriptors([NSSortDescriptor(key: "date",ascending: false)]) for item in sorted { dict.append(item as! NSDictionary) } } completionHandler() }) }
这段代码工作正常。 问题 在于,在运行时,数据将被添加到Firebase数据库中。这就是为什么我必须使用observeEventType而不是observeSingleEventOfType。
observeEventType
observeSingleEventOfType
这意味着在运行时会有一个观察者,并且如果数据已添加到数据库中,myFirebaseFunction则将再次调用其中的块。
myFirebaseFunction
一旦发生这种情况,该应用就会崩溃,因为dispatch_group_leave(group)没有调用dispatch_group_enter(group)。只要我说对了。
dispatch_group_leave(group)
dispatch_group_enter(group)
dispatch_group_enter(group) myFirebaseFunction() { dispatch_group_leave(group) // crash here }
如果将其更改为observeSingleEventOfType,则不会发生崩溃,但是不会观察到新添加到Firebase的数据。
dispatch_group与多个运行的Web服务一起使用的最佳实践是什么?或者我该怎么做才能解决我的问题?非常感谢您的帮助。
PS当前,我正在使用Swift 2.3,但计划将其升级到Swift 3,因此收到能够同时解决这两个问题的答案将非常棒。
如您所述,呼叫dispatch_group_enter和dispatch_group_leave必须保持平衡。在这里,您无法平衡它们,因为仅执行实际实时提取的函数会离开。
dispatch_group_enter
dispatch_group_leave
如果myFirebaseFunction始终在该调度组上执行其工作没有问题,则可以将进入和离开都放在其中,也许使用beginHandler和completedHandler:
func loadStuff() { myFirebaseFunction(beginHandler: { dispatch_group_enter(group) dispatch_group_notify(group, dispatch_get_main_queue()) { print("done") } }, completionHandler: { dispatch_group_leave(group) }) } func myFirebaseFunction(beginHandler: () -> (), completionHandler: () -> ()) { let usersRef = firebase.child("likes") usersRef.observeEventType(.Value, withBlock: { snapshot in beginHandler() if snapshot.exists() { let sorted = (snapshot.value!.allValues as NSArray).sortedArrayUsingDescriptors([NSSortDescriptor(key: "date",ascending: false)]) for item in sorted { dict.append(item as! NSDictionary) } } completionHandler() }) }
在这里,完成处理程序仍将设置为dispatch_group_leaveby loadStuff,但是还有一个begin处理程序将调用dispatch_group_enterand dispatch_group_notify。需要在开始时调用notify的原因是,我们需要确保在调用notify之前已经进入了该组,否则如果该组为空,则notify块将立即执行。
loadStuff
dispatch_group_notify
即使传递给dispatch_group_notify通知的块在组上执行,即使传递给该块的块也只会被调用一次。因此,observeEventType在组上进行每次自动呼叫可能是安全的。然后,在这些功能之外需要等待加载完成的任何时间,您都可以调用notify。
编辑: 由于每次beginHandler调用notify都会被调用,因此此方法实际上会导致每次调用notify块,因此它可能不是理想的选择。
beginHandler
如果您真正需要的仅是第一次调用observeEventType使用该组,则一个选项是具有的两个版本myFirebaseFunction:一个与您已经拥有的版本非常相似,另一个与一起使用observeSingleEventOfType。然后加载的东西可以调用这两个函数,仅dispatch_group_leave作为完成传递给其中一个:
func loadStuff() { dispatch_group_enter(group) myInitialFirebaseFunction() { dispatch_group_leave(group) } dispatch_group_notify(group, dispatch_get_main_queue()) { print("done") } myFirebaseFunction({}) } func myInitialFirebaseFunction(completionHandler: () -> ()) { let usersRef = firebase.child("likes") usersRef.observeSingleEventOfType(.Value, withBlock: { snapshot in processSnapshot(snapshot) completionHandler() }) } func myFirebaseFunction(completionHandler: () -> ()) { let usersRef = firebase.child("likes") usersRef.observeSingleEventOfType(.Value, withBlock: { snapshot in processSnapshot(snapshot) completionHandler() }) } func processSnapshot(snapshot: FDataSnapshot) { if snapshot.exists() { let sorted = (snapshot.value!.allValues as NSArray).sortedArrayUsingDescriptors([NSSortDescriptor(key: "date",ascending: false)]) for item in sorted { dict.append(item as! NSDictionary) } } }
请注意,由于loadStuff在“方法2”中基本上从Firebase加载了两次,因此效率可能不如您所愿。在这种情况下,您可以改用a Bool来确定是否应调用请假:
Bool
var shouldLeaveGroupOnProcess = false func loadStuff() { dispatch_group_enter(group) shouldLeaveGroupOnProcess = true myFirebaseFunction() { if shouldLeaveGroupOnProcess { shouldLeaveGroupOnProcess = false dispatch_group_leave(group) } } dispatch_group_notify(group, dispatch_get_main_queue()) { print("done") } } func myFirebaseFunction(completionHandler: () -> ()) { let usersRef = firebase.child("likes") usersRef.observeEventType(.Value, withBlock: { snapshot in if snapshot.exists() { let sorted = (snapshot.value!.allValues as NSArray).sortedArrayUsingDescriptors([NSSortDescriptor(key: "date",ascending: false)]) for item in sorted { dict.append(item as! NSDictionary) } } completionHandler() }) }
在这里,即使observeEventType在初始加载期间多次调用,也leave可以保证仅被调用一次,并且不会发生崩溃。
leave
在Swift 3中Dispatch进行了全面的改进(它是面向对象的),因此在两者上都能很好地工作的代码并不是一件真正的事情:)
但是以上三种方法中每种方法的概念都是相同的。在Swift 3中
DispatchGroup
enter
notify