2009-05-30 9 views
5

ich eine Methode nenne, die in einem Hintergrund-Thread geht:Warum gibt es keinen Autorelease-Pool, wenn ich performanceSelectorInBackground :?

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

dann habe ich diese Methode Implementierung, die durch den Wähler aufgerufen wird:

- (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 ich dort einen Autofreigabepool erstellen für diesen Thread, habe ich immer diese Fehlermeldung erhalten:

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) 

Wenn ich den Autofreigabepool wegzunehmen, erhalte ich eine ganze Reihe von Nachrichten wie diese. Ich habe auch versucht, einen Autorelease-Pool um den Aufruf von performSelectorInBackground zu erstellen, aber das hilft nicht.

Ich vermute den Parameter, aber ich weiß nicht, warum der Compiler über eine NSCFNumber beschwert. Fehle ich etwas?

Meine Instanzvariablen sind alle "nichtatomisch". Kann das ein Problem sein?

UPDATE: Ich vermute auch, dass eine Variable zu einem Autorelease-Pool des Hauptthreads hinzugefügt wurde (vielleicht ein Ivar), und jetzt versucht, diese im falschen Autorelease-Pool freizugeben? Wenn ja, wie könnte ich das beheben? (Verdammt, dieses Threading ist komplex;))

+0

Versuchen Sie einen Haltepunkt einstellen auf _NSAutoreleaseNoPool, um zu sehen, wo es aufgerufen wird von – rpetrich

+0

Tangentenfrage: Hier wird ein neuer Controller, der lokal in diesem Thread zugewiesen ist, zu einem globalen Array hinzugefügt, und auch seine Ansicht wird als Unteransicht hinzugefügt. Ist das ein Problem, dass das Objekt in einem anderen Pool als seinem Container erstellt wird? –

+0

@dk sollten Sie nicht eine tangentiale Frage stellen, stellen Sie eine separate Frage! Trotzdem rate ich dringend davon ab, UI-bezogene Objekte (Controller und Views) in einem Nicht-Haupt-Thread zu erstellen. Das ist eine Katastrophe, die darauf wartet, passiert zu sein. – Yuji

Antwort

6

Wahrscheinlich ist der Grund dafür, dass das ausgelaufene Objekt (eine NSNumber), ein Parameter von außerhalb des Threads übergeben wird. Daher gehört diese Variable zu dem aufrufenden Thread (und seinem Autorelease-Pool)

Der Grund, dass der Autorelease-Pool um den Thread-Aufruf nicht funktioniert, ist, weil der Thread-Ersteller (performSelectorInbackground) sofort zurückgibt, höchstwahrscheinlich während Thread läuft noch.

Ich schlage vor, dass Sie eine Freigabe für den Parameter Ihres Selektors machen, nachdem Sie ihn als Argument übergeben haben.

+1

Ja, das Übergeben von automatisch freigegebenen Objekten in neue Threads kann sehr seltsames Verhalten verursachen. –

2

Ich stimme zu, dass der Grund dafür wahrscheinlich darin liegt, dass das ausgelaufene Objekt (eine NSNumber) ein Parameter ist, der von außerhalb des Threads übergeben wurde. Daher gehört diese Variable auf den aufrufenden Thread (und seinen Autofreigabepool)

Der aufrufende Thread NSAutoreleasePool verwenden soll, und ich schlage vor, dass Sie eine behalten Anweisung an Ihre Parameter wie hinzufügen:

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

    .... 

    [arPool release]; 
    } 
Verwandte Themen