iphone cocoa multithreading

iphone - -[NSOperationQueue operations] devuelve una matriz vacía cuando no debería?



cocoa multithreading (5)

No hay idea de por qué está viendo este comportamiento, pero como una solución pura podría mantener sus propias referencias a las operaciones individuales a medida que se agregan a la cola.

Estoy escribiendo una aplicación que realiza una carga de imágenes asíncrona en la pantalla. Lo tengo configurado para que NO sea concurrente (es decir, genera un hilo y lo ejecuta uno a la vez), así que solo he reemplazado la función [NSOperation main] en mi subclase NSOperation.

De todas formas, cuando agrego todas estas operaciones, quiero poder acceder más tarde a las operaciones en cola para cambiar sus prioridades. Desafortunadamente, cada vez que llamo -[NSOperationQueue operations] , todo lo que obtengo es una matriz vacía. La mejor parte es que después de colocar algunas instrucciones de impresión de consola, los hilos aún están en la cola y se están ejecutando (indicados por impresiones) a pesar de que la matriz está vacía.

¿Lo que da? También eché un vistazo a la cuenta solo para asegurarme de que no todos se están ejecutando de inmediato y ese no parece ser el caso.

¿Algunas ideas? Tirando de mi cabello en este.

EDITAR: También vale la pena mencionar que el mismo código proporciona una matriz completa cuando se ejecuta en el simulador :(


Simplemente no creo que haya suficiente contexto aquí para decir lo que está pasando. Claramente, algo está mal, pero no dice cómo está limitando la concurrencia, cómo está probando para ver los objetos en ejecución, etc.

En cuanto al simulador frente al iPhone, NSOperations puede actuar de manera muy diferente entre los dos, ya que todos los Mac basados ​​en Intel son multiprocesador, y no hay iPhones. Dependiendo de cómo intente limitar la concurrencia, podría encontrarse en una situación en la que no poder ejecutar en un segundo núcleo impida que se ejecuten cosas, etc. Pero sin más detalles es imposible saberlo.


He visto un comportamiento similar en situaciones de poca memoria. ¿Cuánta memoria estás usando? ¿Está borrando correctamente los cachés y otros datos temporales cuando recibe un mensaje didReceiveMemoryWarning ?


Pasé por las -operations , y descubrí que básicamente está haciendo:

[self->data->lock lock]; NSString* copy = [[self->data->operations copy] autorelease]; [self->data->lock unlock]; return copy;

excepto, después de llamar -autorelease , las instrucciones subsiguientes sobrescriben el registro que contiene el único puntero a la nueva copia de la cola de operaciones. La persona que llama simplemente obtiene un valor de retorno nil . El campo " data " es una instancia de una clase interna llamada _NSOperationQueueData que tiene campos:

NSRecursiveLock* lock; NSArray* operations;

Mi solución fue subclasificar y anular las -operations , siguiendo la misma lógica, pero en realidad devolviendo la copia de la matriz. NSOperationQueue algunos controles de cordura para rescatarme si las NSOperationQueue internas de NSOperationQueue no son compatibles con esta corrección. Esta reimplementación solo se llama si una llamada a [super operations] de hecho devuelve nil .

Esto podría romperse en futuras versiones del sistema operativo si Apple cambiara la estructura interna, pero de alguna manera evitara arreglar este error.

#if TARGET_OS_IPHONE #import <objc/runtime.h> @interface _DLOperationQueueData : NSObject { @public id lock; // <NSLocking> NSArray* operations; } @end @implementation _DLOperationQueueData; @end @interface _DLOperationQueueFix : NSObject { @public _DLOperationQueueData* data; } @end @implementation _DLOperationQueueFix; @end #endif @implementation DLOperationQueue #if TARGET_OS_IPHONE -(NSArray*) operations { NSArray* operations = [super operations]; if (operations != nil) { return operations; } _DLOperationQueueFix* fix = (_DLOperationQueueFix*) self; _DLOperationQueueData* data = fix->data; if (strcmp(class_getName([data class]), "_NSOperationQueueData") != 0) { // this hack knows only the structure of _NSOperationQueueData // anything else, bail return operations; } if ([data->lock conformsToProtocol: @protocol(NSLocking)] == NO) { return operations; // not a lock, bail } [data->lock lock]; operations = [[data->operations copy] autorelease]; [data->lock unlock]; return operations; // you forgot something, Apple. } #endif @end

El archivo de encabezado es:

@interface DLOperationQueue : NSOperationQueue {} #if TARGET_OS_IPHONE -(NSArray*) operations; #endif @end


Me encontré con el mismo problema. Código más simple que el que uso en una aplicación OS X, y sin embargo [operaciones de operación de mi operación] siempre devuelve nulo. Estaba planeando usar eso para evitar duplicar las consultas. Esto está en iPhone OS 2.2.1. Claro parece un error. Gracias por el código, puedo usarlo, o simplemente usar mi propio espejo de la cola.

Esto no está en el simulador, y confirmo que agregué 20 o exactamente las mismas copias del trabajo, ¡que se alinean muy bien y hacen el trabajo 19 veces más!

Es un código bastante simple. No estoy usando casi ningún recuerdo, esto es en el lanzamiento de una aplicación que aún no tiene ninguna interfaz de usuario.

--Tom