EXC mauvaise INSTRUCTION (code=EXC I386 INVOP, subcode=0x0) sur le sémaphore d'expédition disposer
je reçois EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) sur dispatch_semaphore_dispose mais je ne sais pas vraiment comment trouver la cause profonde de cela. Mon code utilise dispatch_async, dispatch_group_enter et ainsi de suite.
mise à jour: La cause du crash est due au fait que webserviceCall (voir code ci-dessous) n'appelle jamais oncompletionet que lorsque le code est lancé à nouveau, J'ai eu L'instruction error EXC_BAD_INSTRUCTION. J'ai vérifié c'est effectivement le cas, mais vous ne savez pas pourquoi ou comment l'empêcher.
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
});
});
8 réponses
à Partir de votre trace de la pile EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
est survenue parce que dispatch_group_t
a été libéré alors qu'il était encore verrouillé (en attente de dispatch_group_leave
).
Selon ce que vous avez trouvé, c'est ce qui s'est passé :
dispatch_group_t group
a été créé.group
conserver count = 1.-[self webservice:onCompletion:]
capturé l'group
.group
conserver count = 2.dispatch_async(...., ^{ dispatch_group_wait(group, ...) ... });
capturé l'group
nouveau.group
's compte de retenue = 3.- quitter la portée actuelle.
group
a été libéré.group
conserver count = 2. dispatch_group_leave
n'a jamais été appelé.dispatch_group_wait
était temps mort.dispatch_async
bloc terminé.group
a été libéré.group
conserver count = 1.- vous avez rappelé cette méthode. Lorsque
-[self webservice:onCompletion:]
a été appelé de nouveau, l'ancienonCompletion
bloc a été remplacé par le nouveau. Donc, la vieillegroup
a publier.group
conserver count = 0.group
a été libéré. Qui ont abouti à l'EXC_BAD_INSTRUCTION
.
Pour résoudre ce problème, je suggère que vous devriez chercher à savoir pourquoi -[self webservice:onCompletion:]
ne pas appeler onCompletion
bloquez et réparez. Ensuite, assurez-vous que le prochain appel à la méthode se produira après l'appel précédent a terminé.
dans le cas où vous permettez à la méthode d'être appelée plusieurs fois si les appels précédents ont fini ou non, vous pourriez trouver quelqu'un de tenir group
pour vous :
- vous pouvez changer le délai de 2 secondes à
DISPATCH_TIME_FOREVER
ou un délai raisonnable que tous-[self webservice:onCompletion]
doivent appeleronCompletion
blocs par le temps. De sorte que le blocdispatch_async(...)
va la garder pour vous.
Ou - Vous pouvez ajouter
group
dans une collection, commeNSMutableArray
.
je pense que c'est la meilleure approche pour créer une classe dédiée à cette action. Lorsque vous voulez faire des appels à webservice, vous créez alors un objet de la classe, appelez la méthode dessus avec le bloc d'achèvement qui lui passera qui libérera l'objet. Dans la classe, il y a un ivar dispatch_group_t
ou dispatch_semaphore_t
.
Mon problème a été pris IBOutlet
mais ne s'est pas connecté avec interface builder et utiliser dans le fichier swift.
j'ai eu une autre question qui m'a amenée à cette question, qui sera probablement plus fréquente que la question de la réponse exagérée dans la réponse acceptée.
la cause fondamentale est que notre bloc d'achèvement a été appelé deux fois en raison du mauvais si/d'autre fallthrough dans le réseau du gestionnaire, conduisant à deux appels d' 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ébogage via le groupe de dispatch_ count
Sur le EXC_BAD_INSTRUCTION
, vous devriez avoir accès à votre dispatch_group dans le débogueur. Imprimez le groupe dispatch_group et vous verrez:
<OS_dispatch_group: group[0x60800008bf40] = { xrefcnt = 0x2, refcnt = 0x1, port = 0x0, count = -1, waiters = 0 }>
Quand vous voyez count = -1
indique que vous avez quitté le groupe dispatch_. Assurez-vous de dispatch_enter
et dispatch_leave
le groupe en paires.
mon problème était que je créais des objets que je voulais stocker dans Unnsmutable dictionnaire mais je n'ai jamais initialisé le dictionnaire. Par conséquent, les objets ont été supprimés par la collecte des ordures et de briser plus tard. Vérifiez que vous avez au moins une référence forte aux objets avec lesquels vous interagissez.
Dans mon cas:
PHImageRequestOptions *requestOptions = [PHImageRequestOptions new];
requestOptions.synchronous = NO;
essayait de le faire avec dispatch_group
Parfois, tout ce qu'il faut pour obtenir un EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
manque un return
déclaration.
Il a certainement été mon cas.
j'ai atterri ici à cause d'un XCTestCase, dans lequel j'ai désactivé la plupart des tests en les préfixant par " no_ " comme dans no_testBackgroundAdding. Une fois que j'ai remarqué que la plupart des réponses avaient quelque chose à voir avec les serrures et le threading, j'ai réalisé que le test contenait quelques exemples de XCTestExpectation avec des attenteforexpectations correspondantes. Ils étaient tous dans les tests pour handicapés, mais apparemment Xcode les évaluait encore à un certain niveau.
a la fin j'ai trouvé une XCTestExpectation cela a été défini comme @propriété mais manquait @synthétiser. Une fois que j'ai ajouté la directive synthize, L'instruction EXC_BAD_ a disparu.
Mon problème était que c'était dans mon init(). Probablement le "faible" l'a tué alors que l'init n'était pas terminé. Je l'ai déplacée de l'intérieur et ça a résolu mon problème.