在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:]
捕获了该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
块被replace为新的。 所以,老group
被释放了。group
的保留数= 0group
被释放。 这导致了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_t
或dispatch_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_enter
和dispatch_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消失了。