2009-11-08 20 views
5

Tengo una situación en la que soy perezoso al cargar imágenes de www.
Es una lista de elementos, cuando se toca un elemento, se envía una vista de detalle a un controlador de navegación.Cocoa-Touch: performSelectorOnMainThread: comportamiento extraño + crash

En esa vista detallada, el elemento tiene una imagen, que primero es una imagen predeterminada, y quiero comenzar a cargar su imagen desde una URL.

Así que lo que hago es crear un objeto que una vez inicializado separa un nuevo hilo que a su vez carga el contenido y luego notifica a mi opinión de que los datos están cargados:

// in MyLoader: 
- (MyLoader *)initWithUrl:(NSURL *)url requester:(id)requester { 
    self.url = url; 
    self.requester = requester; // both are nonatomic, retain properties 
    [self performSelectorInBackground:@selector(loadIt) withObject:nil]; 
} 

- (void)loadIt { 
    NSAutoreleasePool *arp = [[NSAutoreleasePool alloc] init]; 
    NSData *data = [NSData dataWithContentsOfURL:url]; 
    [requester performSelectorOnMainThread:@selector(dataReady) withObject:data waitUntilDone:YES; 
    [arp release]; 
} 

// in MyRequester: 
- (void)somewhere { 
    MyLoader *loader = [[[MyLoader] alloc] initWithUrl:someUrl requester:self] autorelease]; 
    // then I retain loader somewhere, it's more complicated but I have verified that it's properly retained. 
} 

Unas pocas notas:

  1. Primero pensé que podría haber un problema con algunas de las variables. Puse un punto de interrupción justo antes de performSelectorOnMainThread y confirmé que data y requester estaban bien.

  2. Entonces pensé que era causada por la que pasa el NSData a través de los hilos, por lo que cambió withObject:nil. Todavía se cuelga.

  3. Cuando investigué más, el accidente fue muy extraño. Especifiqué waitUntilDone:YES, he colocado un punto de interrupción en requester 's dataReady. Pero la llamada performSelectorOnMainThread regresa (alcanza el punto de interrupción después de ella) sin alcanzar el punto de interrupción dentro de dataReady. Por cierto, el cuerpo de - (void)dataReady:(NSData*) por ahora solo contiene int x = 1; (para colocar un punto de interrupción). Además, he intentado configurar waitUntilDone:NO, todavía se bloquea.

  4. El selector no se realiza (no se alcanza el punto de interrupción), pero el bloqueo se produce poco tiempo después de la llamada.

¿Alguien tiene alguna idea de lo que está mal?

Esto es obvio, pero para ser claros, si solo comento la parte [requester performSelectorOnMainThread..., no se cuelga.

Además, aquí hay un seguimiento de la pila, pero no es útil en absoluto.

#0 0x00a71004 in ___TERMINATING_DUE_TO_UNCAUGHT_EXCEPTION___() 
#1 0x93436e3b in objc_exception_throw() 
#2 0x0028aca6 in __NSThreadPerformPerform() 
#3 0x00a098e1 in CFRunLoopRunSpecific() 
#4 0x00a08c48 in CFRunLoopRunInMode() 
#5 0x0005a78d in GSEventRunModal() 
#6 0x0005a852 in GSEventRun() 
#7 0x0168a003 in UIApplicationMain() 
#8 0x000028d4 in main (argc=1, argv=0xbffff100) at /Users/myName/Document/appName/main.m:14 
+1

Sospecho que hay formas más fáciles de ver la excepción no detectada, pero intente ajustar int retVal = UIApplicationMain (argc, argv, nil, nil); en su archivo main.m con un bloque try/catch y examine o imprima la excepción. Podría dar algunas pistas. Sé que puedo presionar Continuar después de algo así (en el depurador) y, finalmente, imprime la causa. Pero eso puede deberse a algunas configuraciones en mi archivo .gdbinit. Mi.gdbinit tiene algunas cosas de punto de interrupción para NSException ... – wkw

Respuesta

9

tiene:

[requester performSelectorOnMainThread:@selector(dataReady) withObject:data waitUntilDone:YES; 

debería ser:

[requester performSelectorOnMainThread:@selector(dataReady:) withObject:data waitUntilDone:YES; 

aviso: @selector (DataReady :) (con dos puntos) Puesto que usted está pasando un argumento para el método, se presume datos listos se define algo así como:

- (void) dataReady:(NSData *)theData ... 
+1

puntos faltantes, no punto y coma. El colon es parte del nombre del método. – NSResponder

+11

En el futuro, puede ver esto yendo a la configuración de compilación y agregando -Wdedeclared-selector en las otras banderas de advertencia. Esto causará que se emita una advertencia en el caso anterior, donde el selector no coincide con ningún método conocido. –