2010-08-09 15 views
0

Je reçois une erreur EXC_BAD_ACCESS après mon retour d'une méthode de thread dans laquelle j'ai configuré un NSAutoreleasePool. L'endroit de l'échec est à un appel à NSRunLoop. J'essaye d'emballer une bibliothèque de 3ème partie consistant principalement en une classe (appelons la classe de connexion) et son délégué de sorte qu'il se comporte de manière synchrone au lieu d'asynchrone aux classes de client. La classe d'enrobage, appelée NFCConnection, est conforme au protocole délégué et transmise à la méthode setDelegate de Connection dans le constructeur de NFCConnection.Erreur sur NSRunLoop après retour de la méthode thread avec NSAutoreleasePool

La méthode dans laquelle je crée le nouveau thread est comme suit:

- (void)methodA { 
    [NSThread detachNewThreadSelector:@selector(doSomethingImportant) 
          toTarget:self 
          withObject:nil]; 

    while (!callBackInvoked) { 
     [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode  // Error! 
           beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];   
    } 
} 

La méthode de fil, doSomethingImportant, ressemble à ceci:

- (void)doSomethingImportant { 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
    [[Connection instance] somethingImportant];  
    [pool release]; 
} 

L'appel à somethingImportant de connexion entraînera une des les méthodes déléguées à appeler sur le thread principal. Dans chacune de ces méthodes de rappel, je mets la variable callBackMethod à NO, provoquant la fin de la boucle while dans methodA. L'erreur se produit après que doSomethingImportant renvoie mais avant que l'une des méthodes de délégué ne soit appelée. L'erreur EXC_BAD_ACCESS se produit lors de l'appel à NSRunLoop. Voici une partie de la trace de la pile:

#0 0x3138cec0 in objc_msgSend 
#1 0x000100ac in -[Connection ProcessRx_Api_SomethingImportant:] at Connection.m:621 
#2 0x000114fa in +[Connection ProcessRx:] at Connection.m:900 
#3 0x00012758 in -[CommHandling ProcessRx:length:] at CommHandling.m:294 
#4 0x000126b8 in -[CommHandling stream:handleEvent:] at CommHandling.m:331 
#5 0x30a7b958 in -[EAInputStream _streamEventTrigger] 
#6 0x30a7be78 in __streamEventTrigger 
#7 0x323f53a6 in CFRunLoopRunSpecific 
#8 0x323f4c1e in CFRunLoopRunInMode 
#9 0x3373c966 in -[NSRunLoop(NSRunLoop) runMode:beforeDate:] 
#10 0x0000ae66 in -[NFCConnection methodA:] at NFCConnection.m:137 
#11 0x0000bbf2 in -[NFCTestViewController doIt] at NFCTestViewController.m:39 
... 

Maintenant, je peux empêcher l'erreur de se produire du tout et l'API enveloppé semble fonctionner de façon synchrone si je néglige de mettre en place la piscine autorelease dans doSomethingImportant. Mais si je devais faire cela, alors ce qui suit est imprimé dans la console:

2010-08-09 14:54:49.259 ConnetionTest[3353:652f] *** _NSAutoreleaseNoPool(): Object 0x1928b0 of class __NSCFDate autoreleased with no pool in place - just leaking 
Stack: (0x3374ff83 0x33723973 0x3372393f 0x323f78f1 0x3372b913 0x10221 0xc833 0xb045 0x33731acd 0x336dfd15 0x33ad8788) 
2010-08-09 14:54:49.272 ConnetionTest[3353:652f] *** _NSAutoreleaseNoPool(): Object 0x18f800 of class NSCFTimer autoreleased with no pool in place - just leaking 
Stack: (0x3374ff83 0x33723973 0x3372393f 0x3372b93b 0x10221 0xc833 0xb045 0x33731acd 0x336dfd15 0x33ad8788) 

-ce que ces messages ci-dessus d'origine non être libéré en l'instance de classe de connexion? Je suis en train de créer un NSDate mais pas un exemple dont il faut sortir. Même chose avec un NSTimer.

J'essaye de faire la bonne chose ici en installant le NSAutoreleasePool mais il semble que je fasse quelque chose de mal. Cependant, je n'ai pas la moindre idée de ce que cela pourrait être. Toute aide très appréciée!

Rich

Répondre

1

D'abord, vous avez certainement besoin du nouveau thread d'avoir une piscine autorelease, donc ne punt pas à sa résolution. :-)

Cela dit, cela a certaines des caractéristiques d'une version prématurée ou d'une sur-libération quelque part dans le code. Je porterais une attention particulière au délégué de l'objet Connection, car les règles concernant un objet qui retient son délégué sont quelque peu glissantes. (Objets de cacao en général ne pas leurs délégués conservent, mais le code tiers peut -. Et parfois pour de bonnes raisons)

je vais maintenant appeler votre attention sur Tracking Memory Usage. Certaines permutations de MallocDebug et NSZombieEnabled = YES devraient éventuellement révéler le code coupable. Cependant, une fois que vous avez dépassé ce bug, vous pouvez explorer Grand Central Dispatch pour ce genre de choses plutôt que de lancer vos propres threads ... Votre code tel qu'il se présente ressemble probablement à une condition NSC. ou la variable pthread_condition pour être strictement correcte. Bien que vous puissiez vous en passer beaucoup avec le matériel actuel, ces types d'accès partagés non synchronisés peuvent facilement provoquer des courses vraiment désagréables.GCD (AKA libdispatch) propose un paradigme propre beaucoup et plus moderne, donc si vous allez apprendre quelque chose de nouveau, il est un beaucoup meilleur investissement que pthreads/NSThread/etc :-)

+0

Merci pour la réponse Kaelin. J'ai déjà considéré GCD mais c'est seulement disponible dans iOS 4 et cette bibliothèque de tiers dans l'exemple est compilée en 3.x. Je vais lire l'article sur l'utilisation de la mémoire de suivi et je me pencherai sur d'autres stratégies de synchronisation pour voir ce que je trouve. – richever