Подтвердить что ты не робот

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

Ответ 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.

Это, безусловно, было моим делом.