2010-07-27 9 views
8

tengo el siguiente método:iPhone - performSelectorOnMainThread con valor de retorno

- (NSMutableArray *)getElements:(NSString *)theURL; 

Y quería saber si hay una manera de llamar a ese método que utiliza performSelectorOnMainThread para que pueda obtener el valor de retorno. Hasta ahora, he tratado con:

myArray = [object performSelectorOnMainThread:@selector(getElements:) 
            withObject:url waitUntilDone:YES]; 

pero no funciona, ya que performSelectorOnMainThread regresa vacía. ¿Cómo podría resolver esto?

Respuesta

12

Bienvenido a un entorno multihilo mi amigo.

Es necesario almacenar el valor de retorno en una variable de instancia o pasar de un objeto por referencia a través de la withObject parámetro:

NSMutableDictionary *myDict; 

[object performSelectorOnMainThread:@selector(getElements:) 
            withObject:&myDict waitUntilDone:YES]; 

Su prototipo método que ahora debería tener este aspecto:

- (void)getElements:(NSMutableDictionary **)objects; 
+5

Esto no se puede compilar con: "No se puede inicializar un parámetro de tipo 'id' con un valor r de tipo 'NSMutableDictionary **'" – eodabash

3

No puede hacerlo directamente, porque, como usted dice, ese método devuelve vacío.

Por lo tanto, tendría que organizar otra forma de recuperar un valor, por ejemplo, pasando un NSDictionary en lugar de un NSString, y teniendo el método de almacenar el resultado en el diccionario para usted.

2

Tuve que implementar esto recientemente. Gran candidato para añadir una categoría para NSObject para que todos sus objetos pueden hacer esto:

@implementation NSObject (CallSelectorWithObjectOnMainThread) 
- (id)resultFromSelectorOnMainThread:(SEL)selector object:(id)object { 
    NSMutableDictionary *resultDictionary = [NSMutableDictionary dictionaryWithCapacity:1]; 
    NSMutableDictionary *callDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:resultDictionary, @"ResultDictionary", NSStringFromSelector(selector), @"Selector", nil]; 
    if(object) [callDict setValue:object forKey:@"Object"]; 
    [self performSelectorOnMainThread:@selector(callObject:) withObject:callDict waitUntilDone:YES]; 
    return [resultDictionary objectForKey:@"Result"]; 
} 

- (void)callObject:(NSMutableDictionary *)info { 
    id result; 
    SEL selector = NSSelectorFromString([info objectForKey:@"Selector"]); 
    id object = [info objectForKey:@"Object"]; 
    NSMutableDictionary *resultDictionary = [info objectForKey:@"Dictionary"]; 
    if(object) 
    result = [self performSelector:selector withObject:object]; 
    else 
    result = [self performSelector:selector]; 
    if(result) 
    [resultDictionary setValue:result forKey:@"Result"]; 
} 
@end 
+0

+1 Gracias por este Colin. Encontré un par de defectos después de usarlo: callDict necesita ser inicializado con NSMutableDictionary y callObject necesita tener un argumento de método NSMutableDictionary. – TPoschel

+0

@TPoschel ¡Gracias! – Colin

2

tengo solución universal para la llamada de bloqueo asíncrono con el valor de retorno para cualquier tema, no sólo principal. Este ejemplo de hilo principal como performSelectorOnMainThread: withObject: waitUntilDone:

__block id result = nil; 
NSOperationQueue* targetQueue = [NSOperationQueue* mainQueue]; 
// targetQueue is main thread, but it may be queue on any thread. 

[targetQueue addBlockOperation:^{ 
    // performs on target thread. 
    result = [someObject someSelector]; 
}]; 

// wait until operations on targetQueue will finished. 
[targetQueue waitUntilAllOperationsAreFinished]; 

// result is ready here. 

I utiliza esta técnica sólo en el entorno de ARC.