2009-05-30 2 views
5

J'appelle une méthode qui va dans un fil de fond:Pourquoi n'y a-t-il pas de pool de libération automatique lorsque je fais performSelectorInBackground:?

[self performSelectorInBackground:@selector(loadViewControllerWithIndex:) withObject:[NSNumber numberWithInt:viewControllerIndex]]; 

, j'ai cette implémentation de la méthode qui est appelée par le sélecteur:

- (void) loadViewControllerWithIndex:(NSNumber *)indexNumberObj { 
    NSAutoreleasePool *arPool = [[NSAutoreleasePool alloc] init]; 
    NSInteger vcIndex = [indexNumberObj intValue]; 

    Class c; 
    UIViewController *controller = [viewControllers objectAtIndex:vcIndex]; 

    switch (vcIndex) { 
     case 0: 
      c = [MyFirstViewController class]; 
      break; 
     case 1: 
      c = [MySecondViewController class]; 
      break; 
     default: 
      NSLog(@"unknown index for loading view controller: %d", vcIndex); // error 
      break; 
    } 

    if ((NSNull *)controller == [NSNull null]) { 
     controller = [[c alloc] initWithNib]; 
     [viewControllers replaceObjectAtIndex:vcIndex withObject:controller]; 
     [controller release]; 
    } 

    if (controller.view.superview == nil) { 
     UIView *placeholderView = [viewControllerPlaceholderViews objectAtIndex:vcIndex]; 
     [placeholderView addSubview:controller.view]; 
    } 

    [arPool release]; 
} 

Althoug Je ne crée une piscine autorelease il pour ce thread, je reçois toujours cette erreur:

2009-05-30 12:03:09.910 Demo[1827:3f03] *** _NSAutoreleaseNoPool(): Object 0x523e50 of class NSCFNumber autoreleased with no pool in place - just leaking 
Stack: (0x95c83f0f 0x95b90442 0x28d3 0x2d42 0x95b96e0d 0x95b969b4 0x93a00155 0x93a00012) 

Si j'ôterai la piscine autorelease, je reçois un tas de messages comme ceux-ci. J'ai également essayé de créer un pool autorelease autour de l'appel du performSelectorInBackground :, mais cela n'aide pas.

Je suspecte le paramètre, mais je ne sais pas pourquoi le compilateur se plaint d'un NSCFNumber. Est-ce que je manque quelque chose?

Mes variables d'instance sont toutes "non atomiques". Cela peut-il être un problème? MISE À JOUR: Je peux également soupçonner qu'une certaine variable a été ajoutée à un pool d'autorelease du thread principal (peut-être un ivar), et maintenant il essaie de libérer celui-ci dans le mauvais pool autorelease? Si oui, comment pourrais-je résoudre ce problème? (putain, ce truc de threading est complexe;))

+0

Essayez la fixation d'un point d'arrêt sur _NSAutoreleaseNoPool pour voir d'où il est appelé depuis – rpetrich

+0

Tangent question: ici un nouveau contrôleur, alloué localement dans ce thread, est ajouté à un tableau global et sa vue est ajoutée en sous-vue. Est-ce un problème dans la mesure où l'objet est créé dans un pool différent de son conteneur? –

+0

@dk vous ne devriez pas poser une question tangente, posez une question séparée! Quoi qu'il en soit, je déconseille vivement de créer des objets liés à l'interface utilisateur (contrôleurs et vues) dans un thread non principal. C'est une catastrophe qui attend de se produire. – Yuji

Répondre

6

La raison la plus probable est que l'objet divulgué (un NSNumber), est un paramètre passé de l'extérieur du thread. Par conséquent, cette variable appartient au thread appelant (et son pool autorelease)

La raison que le pool autorelease autour de l'appel de thread ne fonctionne pas, est parce que le créateur de thread (performSelectorInbackground) - renvoie immédiatement, très probablement lorsque le le thread est toujours en cours d'exécution.

Je vous suggère de faire une version sur le paramètre de votre sélecteur après l'avoir passé en argument.

+1

Oui, le passage d'objets auto-libérés dans de nouveaux threads peut provoquer un comportement très étrange. –

2

Je suis d'accord que la raison la plus probable est que l'objet divulgué (un NSNumber), est un paramètre passé de l'extérieur du thread. Par conséquent, cette variable appartient au thread appelant (et sa piscine autorelease)

Le thread appelant doit utiliser NSAutoreleasePool et je suggère que vous ajoutez un retain instruction à votre paramètre comme:

- (void) loadViewControllerWithIndex:(NSNumber *)indexNumberObj { 
    NSAutoreleasePool *arPool = [[NSAutoreleasePool alloc] init]; 
    [indexNumberObj retain]; 

    .... 

    [arPool release]; 
    } 
Questions connexes