2010-07-27 8 views
8

je la méthode suivante:iphone - performSelectorOnMainThread avec la valeur de retour

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

Et je voulais savoir s'il y a un moyen d'appeler cette méthode en utilisant performSelectorOnMainThread pour que je puisse obtenir la valeur de retour. Jusqu'à présent, je l'ai essayé avec:

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

mais il ne fonctionne pas, car performSelectorOnMainThread retourne void. Comment pourrais-je résoudre ceci?

Répondre

12

Bienvenue dans un environnement multi-thread mon ami.

Vous aurez besoin de stocker la valeur de retour dans une variable d'instance ou passer dans un objet par référence à travers le paramètre withObject:

NSMutableDictionary *myDict; 

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

Votre prototype de méthode devrait ressembler à ceci:

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

Echec de la compilation avec: "Impossible d'initialiser un paramètre de type 'id' avec un rvalue de type 'NSMutableDictionary **'" – eodabash

3

Vous ne pouvez pas le faire directement, car, comme vous le dites, cette méthode renvoie void. Donc, vous devrez arranger une autre façon de récupérer une valeur, par exemple en passant un NSDictionary au lieu d'un NSString, et avoir la méthode stocker le résultat dans le dictionnaire pour vous.

2

A dû mettre en application ceci récemment. Candidat idéal pour ajouter une catégorie à NSObject afin que tous vos objets peuvent le faire:

@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 Merci pour ce Colin. J'ai trouvé quelques défauts après l'avoir utilisé: callDict doit être initialisé avec NSMutableDictionary et callObject doit avoir un argument de méthode NSMutableDictionary. – TPoschel

+0

@TPoschel Merci! – Colin

2

Je solution universelle pour les appels de blocage async avec la valeur de retour pour un thread, non seulement principal. Cet exemple pour fil conducteur comme 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. 

Je ne ai utilisé cette technique dans un environnement ARC.

Questions connexes