web-dev-qa-db-fra.com

EXC_BAD_INSTRUCTION (code = EXC_I386_INVOP, sous-code = 0x0) sur dispatch_semaphore_dispose

Je reçois EXC_BAD_INSTRUCTION (code = EXC_I386_INVOP, sous-code = 0x0) sur dispatch_semaphore_dispose mais je ne sais pas vraiment comment en rechercher la cause. Mon code utilise dispatch_async, dispatch_group_enter, etc.

UPDATE: La cause de l’incident est due au fait que webserviceCall (voir le code ci-dessous) n’appelle jamais onCompletion et que lorsque le code a été exécuté à nouveau, j’ai reçu l’erreur EXC_BAD_INSTRUCTION. J'ai vérifié que c'était bien le cas, mais je ne savais pas pourquoi ni comment empêcher cela.

enter image description here

Code:

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) est apparu dans votre trace de pile cardispatch_group_t a été publié alors qu'il était en cours de verrouillage (en attente de dispatch_group_leave) .

D'après ce que vous avez trouvé, c'est ce qui s'est passé:

  • dispatch_group_t group a été créé. group 's hold count = 1.
  • -[self webservice:onCompletion:] a capturé la group. group 's hold count = 2.
  • dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... }); a capturé la group à nouveau. group 's hold count = 3.
  • Quitter la portée actuelle. group a été relâché. group 's hold count = 2.
  • dispatch_group_leave n'a jamais été appelé.
  • dispatch_group_wait était dépassé. Le bloc dispatch_async a été complété. group a été relâché. group 's hold count = 1.
  • Vous avez encore appelé cette méthode. Lorsque -[self webservice:onCompletion:] a été appelé à nouveau, l'ancien bloc onCompletion a été remplacé par le nouveau. Ainsi, l’ancien group a été publié. group 's hold count = 0.group a été désalloué. Cela a abouti à EXC_BAD_INSTRUCTION.

Pour résoudre ce problème, je vous suggère de chercher pourquoi -[self webservice:onCompletion:] n'a pas appelé le bloc onCompletion et de le réparer. Assurez-vous ensuite que le prochain appel à la méthode aura lieu une fois l'appel précédent terminé.  


Si vous permettez à la méthode d'être appelée à plusieurs reprises, que les appels précédents se soient terminés ou non, vous pouvez trouver quelqu'un qui détient group pour vous: 

  • Vous pouvez modifier le délai d'attente de 2 secondes à DISPATCH_TIME_FOREVER ou une durée raisonnable pendant laquelle tous les -[self webservice:onCompletion] doivent appeler leurs blocs onCompletion à la fois. Ainsi, le bloc dans dispatch_async(...) le conservera pour vous.
    OU 
  • Vous pouvez ajouter group à une collection, telle que NSMutableArray.

Je pense que c'est la meilleure approche pour créer une classe de dédicace pour cette action . Lorsque vous souhaitez appeler webservice, vous créez ensuite un objet de la classe, appelez la méthode dessus avec le bloc d'achèvement qui lui est transmis et qui libérera l'objet. Dans la classe, il existe un ivar de dispatch_group_t ou dispatch_semaphore_t.

38
3329

Mon problème a été pris IBOutlet mais ne s'est pas connecté avec le constructeur d'interface et en utilisant dans le fichier Swift.

7
Mrugesh Tank

J'ai eu un problème différent qui m'a amené à cette question, qui sera probablement plus commune que la question de la libération conditionnelle dans la réponse acceptée.

La cause première était que notre bloc d'achèvement était appelé deux fois en raison d'un échec si/sinon du gestionnaire de réseau, entraînant deux appels de dispatch_group_leave pour chaque appel à dispatch_group_enter.

Bloc d'achèvement appelé plusieurs fois:

dispatch_group_enter(group);
[self badMethodThatCallsMULTIPLECompletions:^(NSString *completion) {

    // this block is called multiple times
    // one `enter` but multiple `leave`

    dispatch_group_leave(group);
}];

Déboguer via la variable count du groupe de dispatch

Sur le EXC_BAD_INSTRUCTION, vous devriez toujours avoir accès à votre dispatch_group dans le débogueur. Imprimez le dispatch_group et vous verrez:

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

Lorsque vous voyez count = -1, cela indique que vous avez dépassé le groupe d'envoi. Assurez-vous de dispatch_enter et dispatch_leave le groupe par paires correspondantes.

5
pkamb

Mon problème était que je créais des objets que je voulais être stockés dans un NSMutableDictionary mais je n'ai jamais initialisé le dictionnaire. Par conséquent, les objets ont été supprimés par la récupération de place et ont été supprimés ultérieurement. Vérifiez que vous avez au moins une forte référence aux objets avec lesquels vous interagissez.

3
mihai

Dans mon cas: 

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

J'essayais de faire cela avec dispatch_group

Parfois, tout ce qu'il faut pour obtenir un EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) est une instruction return manquante.

C'était certainement mon cas.

1
Gabriel

J'ai atterri ici à cause d'un XCTestCase, dans lequel j'avais désactivé la plupart des tests en les préfixant avec «no_», comme dans no_testBackgroundAdding. Une fois que j'ai remarqué que la plupart des réponses avaient un rapport avec les verrous et les threads, j'ai réalisé que le test contenait quelques instances de XCTestExpectation avec waitForExpectations correspondant. Ils étaient tous dans les tests pour les handicapés, mais apparemment, Xcode les évaluait toujours à un certain niveau. 

En fin de compte, j'ai trouvé un XCTestExpectation défini comme @property mais dépourvu de @synthesize. Une fois que j'ai ajouté la directive synthesize, EXC_BAD_INSTRUCTION a disparu. 

0
Elise van Looij

Mon problème était que c'était dans mon init () . Probablement le "moi faible" l'a tué alors que l'init n'était pas fini . Je l'ai déplacé de l'init et cela a résolu mon problème.

0
Yaron Abramovich