EXC_BAD_INSTRUCTION (код = EXC_I386_INVOP, субкод = 0x0) на dispatch_semaphore_dispose
Я получаю EXC_BAD_INSTRUCTION (код = EXC_I386_INVOP, subcode = 0x0) на dispatch_semaphore_dispose, но на самом деле не знаю, как отследить основную причину этого. В моем коде используются dispatch_async, dispatch_group_enter и т.д.
UPDATE:
Причина сбоя связана с тем, что 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
});
});
Ответы
Ответ 1
Из вашей трассировки стека EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
произошло, потому что dispatch_group_t
был выпущен, пока он все еще блокировался (ожидая dispatch_group_leave
).
В соответствии с тем, что вы нашли, это произошло:
-
dispatch_group_t group
. group
сохранить count = 1.
-
-[self webservice:onCompletion:]
зафиксировано group
. group
сохранить count = 2.
-
dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... });
снова зафиксировал group
. group
сохранить count = 3.
- Выход из текущей области.
group
был выпущен. group
сохранить count = 2.
-
dispatch_group_leave
никогда не вызывался.
-
dispatch_group_wait
был тайм-аут. Блок dispatch_async
был завершен. group
был выпущен. group
сохранить count = 1.
- Вы снова вызвали этот метод. Когда
-[self webservice:onCompletion:]
был вызван снова, старый блок onCompletion
был заменен новым. Итак, старый group
был выпущен. group
сохранить count = 0. group
было освобождено. Это привело к EXC_BAD_INSTRUCTION
.
Чтобы исправить это, я предлагаю вам узнать, почему -[self webservice:onCompletion:]
не вызвал блок onCompletion
и исправить его. Затем убедитесь, что следующий вызов метода произойдет после завершения предыдущего вызова.
Если вы позволяете многократно вызывать метод, закончились ли предыдущие вызовы или нет, вы можете найти кого-то для хранения group
для вас:
- Вы можете изменить тайм-аут с 2 секунд до
DISPATCH_TIME_FOREVER
или разумное количество времени, которое все -[self webservice:onCompletion]
должны назвать их блоками onCompletion
к моменту времени. Чтобы блок в dispatch_async(...)
сохранил его для вас.
ИЛИ
- Вы можете добавить
group
в коллекцию, например NSMutableArray
.
Я думаю, что это лучший подход для создания выделенного класса для этого действия. Когда вы хотите совершать вызовы в webservice, вы затем создаете объект класса, вызываете метод на нем с переданным ему блоком завершения, который освободит объект. В классе есть ivar dispatch_group_t
или dispatch_semaphore_t
.
Ответ 2
Моя проблема была взята IBOutlet
, но не подключалась к конструктору интерфейса и использовалась в быстром файле.
Ответ 3
У меня была другая проблема, которая привела меня к этому вопросу, который, вероятно, будет более распространенным, чем проблема с чрезмерной репутацией в принятом ответе.
Корневая причина заключалась в том, что наш блок завершения вызывался дважды из-за неудачного провала 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);
}];
Отладка через count
dispatch_group
После EXC_BAD_INSTRUCTION
вас должен быть доступ к вашей диспетчерской группе в отладчике. Распечатайте группу dispatch_group, и вы увидите:
<OS_dispatch_group: group[0x60800008bf40] = { xrefcnt = 0x2, refcnt = 0x1, port = 0x0, count = -1, waiters = 0 }>
Когда вы увидите count = -1
это означает, что вы count = -1
группу dispatch_group. Обязательно dispatch_enter
и dispatch_leave
группу в согласованных парах.
Ответ 4
Моя проблема заключалась в том, что я создавал объекты, которые я хотел бы хранить в NSMutableDictionary, но я никогда не инициализировал словарь. Таким образом, объекты были удалены сборкой мусора и взломали позже. Убедитесь, что у вас есть хотя бы одна сильная ссылка на объекты, с которыми вы взаимодействуете.
Ответ 5
В моем случае:
PHImageRequestOptions *requestOptions = [PHImageRequestOptions new];
requestOptions.synchronous = NO;
пытался сделать это с помощью dispatch_group
Ответ 6
Я приземлился здесь из-за XCTestCase, в котором я отключил большинство тестов, префикс их "no_", как в no_testBackgroundAdding. Как только я заметил, что большинство ответов связано с блокировками и потоками, я понял, что тест содержит несколько экземпляров XCTestExpectation с соответствующими waitForExpectations. Все они были в тестах с отключением, но, по-видимому, Xcode все еще оценивал их на определенном уровне.
В конце я нашел XCTest Expectation, который был определен как @property, но не имел @synthesize. Когда я добавил директиву синтеза, EXC_BAD_INSTRUCTION исчез.
Ответ 7
Иногда все, что требуется для получения EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
является отсутствующим оператором return
.
Это, безусловно, было моим делом.