在dispatch_semaphore_dispose上的EXC_BAD_INSTRUCTION(code = EXC_I386_INVOP,子码= 0x0)

我在dispatch_semaphore_dispose上得到了EXC_BAD_INSTRUCTION(code = EXC_I386_INVOP,subcode = 0x0),但是并不知道如何find这个的根本原因。 我的代码使用dispatch_async,dispatch_group_enter等。

更新:崩溃的原因是因为webserviceCall(请参阅下面的代码)永远不会调用onCompletion,并再次运行代码时,我得到了错误EXC_BAD_INSTRUCTION。 我证实这确实是这样,但不知道为什么或如何防止这种情况。

在这里输入图像说明

码:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); dispatch_group_t group = dispatch_group_create(); for (...) { if (...) { dispatch_group_enter(group); dispatch_async(queue, ^{ [self webserviceCall:url onCompletion:^{ dispatch_group_leave(group); }]; }); } } dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC))); dispatch_sync(queue, ^{ // call completion handler passed in by caller }); }); 

从堆栈跟踪中,发生了EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)因为dispatch_group_t在它仍然locking(等待dispatch_group_leave )时被释放

根据你的发现,这是发生了什么事情:

  • dispatch_group_t group已创build。 group的保留数= 1。
  • -[self webservice:onCompletion:]捕获了该groupgroup的保留数= 2。
  • dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... }); 再次夺取了该groupgroup的保留数= 3。
  • 退出当前范围。 group被释放。 group的保留数= 2。
  • dispatch_group_leave从未被调用。
  • dispatch_group_wait超时。 dispatch_async块已完成。 group被释放。 group的保留数= 1。
  • 你再次调用这个方法。 当-[self webservice:onCompletion:]被再次调用时,旧的onCompletion块被replace为新的。 所以,老group被释放了。 group的保留数= 0 group被释放。 这导致了EXC_BAD_INSTRUCTION

为了解决这个问题,我build议你应该找出为什么-[self webservice:onCompletion:]没有调用onCompletion块,并修复它。 然后确保在先前的呼叫完成之后下一次调用该方法。


如果您允许先前的呼叫完成与否,您可以多次调用该方法,您可能会发现有人为您保留group

  • 您可以DISPATCH_TIME_FOREVER从2秒更改为DISPATCH_TIME_FOREVER或者一段合理的时间,以使所有-[self webservice:onCompletion]应该在时间之前调用它们的onCompletion块。 以便dispatch_async(...)中的块将为您保留它。
    要么
  • 您可以将group添加到集合中,例如NSMutableArray

我认为这是为这个行动创造一个专门的class级的最好方法 。 当你想调用webservice ,然后创build一个类的对象,调用它的方法与传递给它的完成块将释放该对象。 在课堂上,有一个dispatch_group_tdispatch_semaphore_t的ivar。

我的问题是采取了IBOutlet但没有连接接口生成器,并在swift文件中使用。

我的问题是,我创build的对象,我想存储在一个NSMutableDictionary但我从来没有初始化字典。 因此,这些对象被垃圾收集和后来的破解删除。 检查是否至less有一个与您正在交互的对象的强引用。

我遇到了一个稍微不同的问题,这个问题给我带来了这个问题,这个问题可能比公认的答案中的超额发行更为常见。

根本原因是我们的完成块被调用两次,因为networking处理程序中的if / else不好通过,导致dispatch_group_leave每调用dispatch_group_enter两次。

在EXC_BAD_INSTRUCTION之后,您应该仍然可以访问debugging器中的dispatch_group。 打印dispatch_group,你会看到:

<OS_dispatch_group: group[0x60800008bf40] = { xrefcnt = 0x2, refcnt = 0x1, port = 0x0, count = -1, waiters = 0 }>

当您看到count = -1 ,表示您已经超出dispatch_group。 请务必以匹配的方式dispatch_enterdispatch_leave组。

在我的情况下:

 PHImageRequestOptions *requestOptions = [PHImageRequestOptions new]; requestOptions.synchronous = NO; 

试图用dispatch_group来做到这一点

因为XCTestCase,我在这里着陆,在这里我通过在no_testBackgroundAdding中加上'no_'作为前缀来禁用大多数testing。 一旦我注意到大部分的答案都与锁和线程有关,我意识到这个testing包含了XCTestExpectation的几个实例和相应的waitForExpectations。 他们都在禁用testing,但显然Xcode仍然在一定程度上评估他们。

最后我发现了一个被定义为@property但缺less@synthesize的XCTestExpectation。 一旦我添加了合成指令,EXC_BAD_INSTRUCTION消失了。