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

时间:2014-06-21 02:40:52

标签: ios objective-c exception grand-central-dispatch

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

更新: 崩溃的原因是因为webserviceCall(请参阅下面的代码)从不调用onCompletion,当代码再次运行时,我收到错误EXC_BAD_INSTRUCTION。我确认情况确实如此,但不确定为什么或如何防止这种情况。

enter image description here

代码:

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
    });
});

8 个答案:

答案 0 :(得分:40)

从您的堆栈跟踪中发现EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0),因为 dispatch_group_t在仍然锁定(等待dispatch_group_leave时被释放。

根据你的发现,这就是发生的事情:

  • dispatch_group_t group已创建。 group的保留计数= 1。
  • -[self webservice:onCompletion:]抓获了group group的保留计数= 2。
  • dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... });再次抓获group group的保留计数= 3。
  • 退出当前范围。 group已被释放。 group的保留计数= 2。
  • dispatch_group_leave从未被召唤过。
  • dispatch_group_wait超时。 dispatch_async块已完成。 group已被释放。 group的保留计数= 1。
  • 您再次调用此方法。再次调用-[self webservice:onCompletion:]时,旧onCompletion块将替换为新块。所以,旧的group被释放了。 group的保留计数= 0。 group已取消分配。结果是EXC_BAD_INSTRUCTION

要解决此问题,我建议你应该找出为什么-[self webservice:onCompletion:]没有调用onCompletion阻止并修复它。然后确保在上一次调用完成后,下一次调用该方法。


如果您允许多次调用该方法,无论之前的调用是否完成,您可能会找到某人为您保留group

  • 您可以将超时时间从2秒更改为DISPATCH_TIME_FOREVER或将所有-[self webservice:onCompletion]按时间调用onCompletion块的合理时间更改。因此dispatch_async(...)中的区块会为您保留。
    或者
  • 您可以将group添加到集合中,例如NSMutableArray

我认为是为此操作创建专用类的最佳方法。当你想调用 webservice 时,你就创建了一个类的对象,调用它上面的方法,并将完成块传递给它,它将释放该对象。在课堂上,有一个dispatch_group_tdispatch_semaphore_t的ivar。

答案 1 :(得分:7)

我的问题是REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE Image_Name latest d8dcd701981e About an hour ago 6.565 GB ,但没有与界面构建器连接并在swift文件中使用。

答案 2 :(得分:5)

我有一个不同的问题让我想到了这个问题,这个问题可能比接受答案中的过度发布问题更常见。

根本原因是我们的完成块被称为两次,因为网络处理程序中的if / else掉落不好,导致每次调用dispatch_group_leave两次dispatch_group_enter }。

多次调用完成块:

dispatch_group_enter(group);
[self badMethodThatCallsMULTIPLECompletions:^(NSString *completion) {

    // this block is called multiple times
    // one `enter` but multiple `leave`

    dispatch_group_leave(group);
}];

通过dispatch_group的count

进行调试

EXC_BAD_INSTRUCTION后,您仍然可以在调试器中访问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组配对。

答案 3 :(得分:4)

我的问题是我正在创建我希望存储在NSMutableDictionary中的对象,但我从未初始化字典。因此,对象被垃圾收集删除并在以后中断。检查您是否至少有一个对您正在与之交互的对象的强引用。

答案 4 :(得分:1)

就我而言:

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

尝试使用dispatch_group执行此操作

答案 5 :(得分:1)

有时,获取EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)所需的只是缺少return语句。

这当然是我的理由。

答案 6 :(得分:0)

由于XCTestCase,我在这里登陆,其中我通过在no_testBackgroundAdding中使用'no_'作为前缀来禁用大多数测试。一旦我注意到大多数答案与锁和线程有关,我意识到测试包含一些XCTestExpectation实例和相应的waitForExpectations。他们都在禁用测试中,但显然Xcode仍然在某种程度上评估它们。

最后我发现XCTestExpectation被定义为@property但缺少@synthesize。一旦我添加了synthesize指令,EXC_BAD_INSTRUCTION就消失了。

答案 7 :(得分:0)

我的问题是它在我的init()中。 初始化未完成时,“弱者”可能杀死了他。 我将其从init中移出,它解决了我的问题。