2009-05-30 2 views
5

sto chiamando un metodo che va in un thread in background:Perché non esiste un pool di autorelease quando eseguoSelectorInBackground :?

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

allora, ho questa implementazione del metodo che viene chiamato dal selettore:

- (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 faccio creare un pool autorelease lì per quel filo, ho sempre arrivare questo errore:

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) 

Se tolgo la piscina autorelease, ho un sacco di messaggi come questi. Ho anche provato a creare un pool di autorelease sulla chiamata di performSelectorInBackground :, ma ciò non aiuta.

Sospetto il parametro, ma non so perché il compilatore si lamenta di un NSCFNumber. Mi sto perdendo qualcosa?

Le mie variabili di istanza sono tutte "non anatomiche". Può essere un problema?

AGGIORNAMENTO: Potrei anche sospettare che qualche variabile sia stata aggiunta a un pool di autorelease del thread principale (forse un ivar), e ora è in grado di rilasciarlo all'interno del pool di autorelease sbagliato? Se è così, come potrei risolverlo? (dannazione, questa discussione è complessa;))

+0

provare a impostare un punto di interruzione su _NSAutoreleaseNoPool per vedere dove viene chiamato da – rpetrich

+0

Domanda tangente: qui un nuovo controller, allocato localmente in questo thread, viene aggiunto a un array globale e anche la sua vista viene aggiunta come sottoview. È un problema in quanto l'oggetto viene creato in un pool diverso rispetto al suo contenitore? –

+0

@dk non si dovrebbe fare una domanda tangente, fare una domanda a parte! Ad ogni modo sconsiglio vivamente di creare oggetti relativi all'interfaccia utente (controller e viste) in un thread non principale. Questo è un disastro in attesa di accadere. – Yuji

risposta

6

Molto probabilmente il motivo è perché l'oggetto trapelato (un NSNumber), è un parametro passato dall'esterno del thread. Quindi, questa variabile appartiene al thread chiamante (e al suo pool autorelease)

Il motivo per cui il pool di autorelease attorno alla chiamata del thread non funziona, è perché il creatore del thread (performSelectorInbackground) - restituisce immediatamente, molto probabilmente mentre il thread è ancora in esecuzione.

Ti suggerisco di rilasciare il parametro del selettore dopo averlo passato come argomento.

+1

Sì, passare oggetti autoreleased in nuovi thread può causare un comportamento molto strano. –

2

Sono d'accordo sul fatto che molto probabilmente la ragione di ciò è perché l'oggetto trapelato (un NSNumber), è un parametro passato dall'esterno del thread. Quindi, questa variabile appartiene al thread chiamante (e la sua piscina autorelease)

il thread chiamante deve utilizzare NSAutoreleasePool e vi suggerisco di aggiungere un'istruzione mantenere al parametro come:

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

    .... 

    [arPool release]; 
    }