2009-05-30 11 views
5

Estoy llamando a un método que va en un subproceso de fondo:¿Por qué no hay pool de autorelease cuando realizo SelectorInBackground :?

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

entonces, tengo esta implementación del método que es llamada por el selector:

- (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 hago crear un grupo de autorelease existe de ese hilo, siempre me sale este error:

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 yo quite la piscina autorelease, consigo un montón de mensajes como estos. También traté de crear un grupo de autorrelease alrededor de la llamada de performSelectorInBackground :, pero eso no ayuda.

Sospecho que el parámetro, pero no sé por qué el compilador se queja de un NSCFNumber. ¿Me estoy perdiendo de algo?

Mis variables de instancia son todas "no atómicas". ¿Puede ser eso un problema?

ACTUALIZACIÓN: también puedo sospechar que alguna variable se ha agregado a un grupo de autorrelease del hilo principal (quizás un ivar), y ahora intenta liberar esa dentro del grupo de autorrelease incorrecto? Si es así, ¿cómo podría solucionarlo? (maldición, esto de enhebrar es complejo;))

+0

Pruebe a establecer un punto de interrupción en _NSAutoreleaseNoPool para ver dónde se llama desde – rpetrich

+0

Pregunta de tangente: aquí se agrega un nuevo controlador, asignado localmente en este subproceso, a un conjunto global y también su vista se agrega como una subvista. ¿Es esto un problema porque el objeto se crea en un conjunto diferente de su contenedor? –

+0

@dk no debería hacer una pregunta tangente, ¡haga una pregunta por separado! De todos modos, recomiendo encarecidamente no crear objetos relacionados con la interfaz de usuario (controladores y vistas) en un hilo no principal. Eso es un desastre esperando a suceder. – Yuji

Respuesta

6

Lo más probable es que el motivo sea que el objeto filtrado (un NSNumber) es un parámetro pasado desde fuera del hilo. Por lo tanto, esta variable pertenece al subproceso de llamada (y su grupo de liberación automática)

El motivo por el que el grupo de liberación automática no funciona, es porque el creador de subprocesos (performSelectorInbackground) - devuelve inmediatamente, probablemente mientras hilo todavía se está ejecutando.

Te sugiero que hagas un lanzamiento en el parámetro de tu selector después de pasarlo como un argumento.

+1

Sí, pasar objetos lanzados automáticamente a nuevos hilos puede causar un comportamiento muy extraño. –

2

Acepto que lo más probable es que el motivo sea que el objeto filtrado (un NSNumber) es un parámetro que se pasa desde fuera del hilo. Por lo tanto, esta variable pertenece al subproceso de la llamada (y su piscina autorelease)

El subproceso de llamada debe utilizar NSAutoreleasePool y sugiero que agregue una instrucción de retener a su parámetro como:

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

    .... 

    [arPool release]; 
    }