tutorials tutorial example ios objective-c exception grand-central-dispatch

ios - tutorial - EXC_BAD_INSTRUCTION(código=EXC_I386_INVOP, subcódigo=0x0) en dispatch_semaphore_dispose



nsoperationqueue swift 3 example (8)

Obtengo EXC_BAD_INSTRUCTION (código = EXC_I386_INVOP, subcódigo = 0x0) en dispatch_semaphore_dispose, pero realmente no sé cómo rastrear la causa raíz de esto. Mi código hace uso de dispatch_async, dispatch_group_enter, etc.

ACTUALIZACIÓN: La causa del bloqueo se debe al hecho de que el servicio web Llamada (ver el código a continuación) nunca llama a Completar y cuando el código se ejecuta nuevamente, recibí el error EXC_BAD_INSTRUCCIÓN. Verifiqué que este es realmente el caso, pero no estoy seguro de por qué o cómo prevenir esto.

Código:

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


A veces, todo lo que se necesita para obtener un EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) es una declaración de return faltante.

Ciertamente fue mi caso.


Aterrize aquí debido a una XCTestCase, en la que he desactivado la mayoría de las pruebas al ponerles un prefijo ''no_'' como en no_testBackgroundAdding. Una vez que noté que la mayoría de las respuestas tenían algo que ver con bloqueos y subprocesos, me di cuenta de que la prueba contenía algunas instancias de XCTestExpectation con la correspondiente waitForExpectations. Todos estaban en las pruebas de discapacidad, pero aparentemente Xcode todavía los estaba evaluando en algún nivel.

Al final encontré una XCTestExpectation que se definió como @property pero que carecía del @synthesize. Una vez que agregué la directiva de sintetizar, desapareció EXC_BAD_INSTRUCTION.


De su rastro de pila, EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) produjo porque dispatch_group_t se liberó mientras aún estaba bloqueado (esperando por dispatch_group_leave ) .

Según lo que encontraste, esto fue lo que sucedió:

  • Se creó el dispatch_group_t group . recuento de retención del group = 1.
  • -[self webservice:onCompletion:] capturó el group . recuento de retención del group = 2.
  • dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... }); capturó el group nuevo. recuento de retención del group = 3.
  • Salga del alcance actual. group fue lanzado. recuento de retención del group = 2.
  • dispatch_group_leave nunca fue llamado.
  • dispatch_group_wait fue tiempo de espera. El bloque dispatch_async se completó. group fue lanzado. recuento de retención del group = 1.
  • Has vuelto a llamar a este método. Cuando -[self webservice:onCompletion:] se llamó de nuevo, el antiguo bloque onCompletion fue reemplazado por el nuevo. Entonces, el viejo group fue liberado. group conteo de retención del group = 0. El group fue desasignado. Eso resultó en EXC_BAD_INSTRUCTION .

Para solucionarlo, le sugiero que averigüe por qué -[self webservice:onCompletion:] no llamó al onCompletion y lo onCompletion . Luego, asegúrese de que la próxima llamada al método se realice después de que la llamada anterior haya finalizado.

En caso de que permita que se llame al método muchas veces, ya sea que las llamadas anteriores hayan finalizado o no, es posible que encuentre a alguien para mantener el group para usted:

  • Puede cambiar el tiempo de espera de 2 segundos a DISPATCH_TIME_FOREVER o una cantidad razonable de tiempo para que todos -[self webservice:onCompletion] llamen a sus bloques onCompletion por el tiempo. De modo que el bloque en dispatch_async(...) lo mantendrá por usted.
    O
  • Puede agregar group a una colección, como NSMutableArray .

Creo que es el mejor enfoque para crear una clase de dedicación para esta acción . Cuando desee realizar llamadas al servicio web , a continuación, cree un objeto de la clase, llame al método con el bloque de finalización que le liberará el objeto. En la clase, hay un ivar de dispatch_group_t o dispatch_semaphore_t .


En mi caso:

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

Estaba tratando de hacer esto con dispatch_group


Mi problema era que estaba creando objetos que quería guardar en un NSMutableDictionary pero nunca inicié el diccionario. Por lo tanto, los objetos fueron eliminados por la recolección de basura y se rompieron más tarde. Compruebe que tiene al menos una referencia fuerte a los objetos con los que está interactuando.


Mi problema era que estaba en mi init (). Probablemente el "yo débil" lo mató mientras que el init no estaba terminado. Lo moví del init y resolvió mi problema.


Mi problema fue tomar IBOutlet pero no se conectó con el constructor de interfaz y el uso en un archivo rápido.


Tuve un problema diferente que me trajo a esta pregunta, que probablemente sea más común que el problema de sobre-publicación en la respuesta aceptada.

La causa raíz fue que nuestro bloque de compleción fue invocado dos veces debido a una falla de if / else en el manejador de red, lo que generó dos llamadas de dispatch_group_leave por cada llamada a dispatch_group_enter .

Bloque de finalización llamado varias veces:

dispatch_group_enter(group); [self badMethodThatCallsMULTIPLECompletions:^(NSString *completion) { // this block is called multiple times // one `enter` but multiple `leave` dispatch_group_leave(group); }];

Depurar a través del count de dispatch_group

En EXC_BAD_INSTRUCTION , aún debe tener acceso a su dispatch_group en el depurador. Imprime el dispatch_group y verás:

<OS_dispatch_group: group[0x60800008bf40] = { xrefcnt = 0x2, refcnt = 0x1, port = 0x0, count = -1, waiters = 0 }>

Cuando vea count = -1 , indica que ya abandonó el grupo dispatch_group. Asegúrese de dispatch_enter y dispatch_leave al grupo en pares coincidentes.