web-dev-qa-db-fra.com

Arguments dans @Selector

Y a-t-il un moyen de passer des arguments dans le sélecteur?

Exemple : J'ai cette méthode

- (void)myMethod:(NSString*)value1 setValue2:(NSString*)value2{

}

et je dois appeler cette fonction à travers un sélecteur qui passe deux arguments.

[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(/*my method*/) userInfo:nil repeats:YES];

Comment puis-je faire ceci?

35
isiaatz

Vous pouvez utiliser la méthode NSTimer:

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds
                                 invocation:(NSInvocation *)invocation
                                    repeats:(BOOL)repeats;

Au lieu de cela, étant donné qu'un objet NSInvocation vous permettra de passer des arguments; Un objet NSInvocation est, en tant que Docs Définir:

un message Objective-C a rendu statique, c'est-à-dire que c'est une action transformée en un objet.

Tout en créant un objet NSTimer à l'aide d'un sélecteur nécessite le format de la méthode:

- (void)timerFireMethod:(NSTimer*)theTimer

Un NSInvocation vous permet de définir la cible, le sélecteur et les arguments que vous transmettez:

SEL selector = @selector(myMethod:setValue2:);

NSMethodSignature *signature = [MyObject instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:selector];

NSString *str1 = @"someString";
NSString *str2 = @"someOtherString";

//The invocation object must retain its arguments
[str1 retain];
[str2 retain];

//Set the arguments
[invocation setTarget:targetInstance];
[invocation setArgument:&str1 atIndex:2];
[invocation setArgument:&str2 atIndex:3];

[NSTimer scheduledTimerWithTimeInterval:0.1 invocation:invocation repeats:YES];

MyObject est la classe que myMethod:setValue2: est déclaré et mis en œuvre sur - instanceMethodSignatureForSelector: est une fonction de commodité déclarée sur NSObject qui retourne un objet NSMethodSignature pour vous, à transmettre à NSInvocation.

Aussi, noter, avec setArgument:atIndex:, les indices pour les arguments à transmettre à la méthode définie comme le sélecteur commencent à l'index 2. de la DOCS:

Les indices 0 et 1 indiquent les arguments cachés eux-mêmes et _cmd, respectivement; Vous devez définir ces valeurs directement avec le SetTarget: et SetSelector: méthodes. Utilisez les indices 2 et plus pour les arguments normalement passés dans un message.

56
Alex Rozanski

Pour scheduledTimerWithTimeInterval:, le sélecteur que vous passez ne peut avoir qu'un seul argument. En outre, son seul argument doit être un NSTimer * objet. En d'autres termes, le sélecteur doit prendre le formulaire suivant:

- (void)timerFireMethod:(NSTimer*)theTimer

Ce que vous pouvez faire est de stocker les arguments du dictionnaire userInfo et appelez le sélecteur souhaité à partir du rappel de la minuterie:

- (void)startMyTimer {
    /* ... Some stuff ... */
    [NSTimer scheduledTimerWithTimeInterval:0.1 
                                     target:self 
                                   selector:@selector(callMyMethod:) 
                                   userInfo:[NSDictionary dictionaryWithObjectsAndKeys:someValue, 
                       @"value1", someOtherValue, @"value2", nil] 
                                    repeats:YES];
}

- (void)callMyMethod:(NSTimer *)theTimer {
    NSString *value1 = [[theTimer userInfo] objectForKey:@"value1"];
    NSString *value2 = [[theTimer userInfo] objectForKey:@"value2"];
    [self myMethod:value1 setValue2:value2];
}
27
Matt Ball

Ressemble à un travail pour les blocs (en supposant que cela soit ciblé pour le léopard des neiges.)

-JCR

2
NSResponder

les blocs semblent une réponse évidente maintenant ... mais il y a une autre idiome très banale dans le runtime classique, cornichez vos arguments dans un seul objet:

 - (void)doMyMethod:(NSDictionary *)userInfo
 {
     [self myMethod: [userInfo objectForKey:@"value1"] setValue2: [userInfo objectForKey:@"value2"]];
 }
 - (void)myMethod:(NSString*)value1 setValue2:(NSString*)value2{

}

maintenant, vous pouvez expédier à

[self performSelector:@selector(doMyMethod:) withObject:@{@"value1":@"value1",@"value2":@"value2"}];
0
Grady Player