取消dispatch_group_notify

时间:2015-11-10 14:19:17

标签: ios grand-central-dispatch

我有一个iOS应用程序,在某些情况下会向服务器创建多个请求以填充屏幕。为了加快速度,我们将请求同时运行。为此,我们使用了dispatch_group_enter,dispatch_group_leave和dispatch_group_notify来确保在返回所有答案之前未填充屏幕:

   performRequest1() // calls dispatch_group_enter before sending the request and dispatch_group_leave when receiving the response
   performRequest2() // calls dispatch_group_enter before sending the request and dispatch_group_leave when receiving the response
   dispatch_group_notify(dispatchGroup, dispatch_get_main_queue()) {
       populateScreen()
   }

当我们收到两个服务器请求的响应之前,用户按下后退按钮时会出现问题。在这种情况下,我们有一个自动取消对服务器(1)的请求的设置,因此不会调用我的成功/失败块(2)。因此,永远不会调用dispatch_group_leave。我认为这样会好(我不希望我的populateScreen()方法被调用)。但iOS似乎有a bug阻止信号量在返回其初始状态之前被释放(3)。换句话说,我被迫调用dispatch_group_enter与dispatch_group_leave完全相同的次数。即使在我只是想跳过并取消所有内容的情况下。

因为对我的申请进行重大改革以取消"取消"发送给视图控制器(4)执行上述代码的操作,我想听听是否有人想要更好的替代方案,等待多个请求完成加载?或者有更好的方法来使用dispatch_group_enter / leave?

修改

一些澄清要点(回应@Rob Napier的答案):

(1)使用AFNetworkings内置的AFHTTPRequestOperation.cancel()函数实现取消

(2)AFNetworking 当然在发送取消操作时调用失败块。但是在我处理的遗留代码中,有一个网络层处理取消操作,因此不会将故障发送到执行请求的类。正如@Rob Napier建议的那样,这很可能是错误的根源,但是在一个大应用程序中改变这种架构设计需要一点勇气......: - 因此,我更愿意找到一个解决方案,我可以在那里取消" abort"取消分配viewController时等待populateScreen()调用。

(3)我知道这篇文章指的是一些不同的东西。然而,我们的应用程序中的崩溃导致Xcode停在与该帖子具有完全相同代码的点:

       0x110bab17a <+61>:  jne    0x110bab19c               ; <+95>
       0x110bab17c <+63>:  leaq   0x189d0(%rip), %rcx       ; "BUG IN CLIENT OF LIBDISPATCH: Use-after-free of dispatch_semaphore_t"
       0x110bab183 <+70>:  movq   %rcx, 0x23316(%rip)       ; gCRAnnotations + 8
       0x110bab18a <+77>:  ud2    
       0x110bab18c <+79>:  leaq   0x18972(%rip), %rcx       ; "BUG IN CLIENT OF LIBDISPATCH: Semaphore/group object deallocated while in use"
       0x110bab193 <+86>:  movq   %rcx, 0x23306(%rip)       ; gCRAnnotations + 8
   ->  0x110bab19a <+93>:  ud2    

好吧,它可能不是iOS中的错误,只是一个非常讨厌的设计决定; - )

(4)这是一个很大的简化,没有列出我们应用程序的整个架构。更确切地说:我们有一个服务层来执行网络请求并创建返回给视图控制器的模型: - )

1 个答案:

答案 0 :(得分:4)

首先,这不是一个错误。您提供的链接正在讨论dispatch_semaphore,这是相关但不同的。在该线程中,他们注意到即使 也不是bug。文档很清楚:“调用[dispatch_group_enter]必须与调用dispatch_group_leave进行平衡。”这是预期的行为。

  

在这种情况下,我们有一个自动取消对服务器的请求的设置,因此不会调用我的成功/失败块。

这是错误的。无论你在这里用“取消”来表示什么,都应该产生一个失败条件,导致调用失败块。例如,如果您在cancel上致电NSURLSessionTask,代表将收到错误消息。您的performRequest()需要这样做。你是如何实施“取消?”的

这意味着取消时会调用populateScreen()。这应该没问题,因为你的系统必须已经能够处理请求错误,而取消只是另一种错误。

作为一个单独的问题,如果上面的代码在视图控制器中,它可能在错误的地方。视图控制器不应该进行网络呼叫并等待结果。他们应该只观察他们的模型。每当模型发生变化时,它们都应该改变。他们应该将用户的请求传递给模型,让模型与网络通信。在这种特殊情况下,这可能只是将问题从视图控制器移动到模型,因此可能不会改变很多事情。但这意味着视图控制器应该能够在取消完成之前解除分配。这很重要,因为视图控制器在弹出后不应该被保留。