it-swarm.com.ru

EXC_BAD_INSTRUCTION (код = EXC_I386_INVOP, субкод = 0x0) для dispatch_semaphore_dispose

Я получаю EXC_BAD_INSTRUCTION (code = EXC_I386_INVOP, subcode = 0x0) на dispatch_semaphore_dispose, но на самом деле не знаю, как отследить основную причину этого. Мой код использует 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
    });
});
33
Boon

Из вашей трассировки стека, EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) произошла, потому чтоdispatch_group_t был освобожден, пока он все еще блокировался (ожидал dispatch_group_leave) .

Согласно тому, что вы нашли, это было то, что произошло:

  • dispatch_group_t group был создан. group's retain count = 1.
  • -[self webservice:onCompletion:] захватил group. group's retain count = 2.
  • dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... }); снова захватил group. group's retain count = 3.
  • Выход из текущей области. group был освобожден. group's retain count = 2.
  • dispatch_group_leave никогда не вызывался.
  • dispatch_group_wait истекло время ожидания. Блок dispatch_async был завершен. group был освобожден. group's retain count = 1.
  • Вы снова вызвали этот метод. При повторном вызове -[self webservice:onCompletion:] старый блок onCompletion был заменен новым. Итак, старая group была освобождена. group's retain count = 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_t или dispatch_semaphore_t.

38
3329

Моя проблема была принята IBOutlet, но не соединялась со сборщиком интерфейса и не использовалась в файле Swift.

7
Mrugesh Tank

У меня была другая проблема, которая привела меня к этому вопросу, который, вероятно, будет более распространенным, чем проблема перевыпуска в принятом ответе.

Основной причиной было то, что наш блок завершения вызывался дважды из-за плохого падения 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 в отладчике. Распечатайте группу 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 группу в совпадающих парах.

5
pkamb

Моя проблема заключалась в том, что я создавал объекты, которые я хотел сохранить в NSMutableDictionary, но я никогда не инициализировал словарь. Поэтому объекты удалялись сборкой мусора и позже ломались. Убедитесь, что у вас есть хотя бы одна сильная ссылка на объекты, с которыми вы взаимодействуете.

3
mihai

В моем случае: 

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

Пытался сделать это с dispatch_group

1
Zaporozhchenko Aleksandr

Иногда все, что нужно для получения EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0), - это отсутствующий оператор return.

Это конечно был мой случай.

1
Gabriel

Я попал сюда из-за XCTestCase, в котором я отключил большинство тестов, поставив перед ними префикс «no_», как в no_testBackgroundAdding. Как только я заметил, что большинство ответов связано с блокировками и потоками, я понял, что тест содержит несколько экземпляров XCTestExpectation с соответствующими waitForExpectations. Все они были в отключенных тестах, но, видимо, Xcode все еще оценивал их на каком-то уровне. 

В конце концов я нашел XCTestExpectation, который был определен как @property, но в нем не было @synthesize. Как только я добавил директиву синтеза, EXC_BAD_INSTRUCTION исчезла. 

0
Elise van Looij

Моя проблема заключалась в том, что это было в моем init () . Вероятно, "слабое я" убило его, в то время как init не было закончено .. Я переместил его из init, и это решило мою проблему.

0
Yaron Abramovich