149 votes

Objective-C : Appel de sélecteurs avec plusieurs arguments

Dans MyClass.m, j'ai défini

- (void) myTest: (NSString *) withAString{
    NSLog(@"hi, %@", withAString);
}

et la déclaration appropriée dans MyClass.h . Plus tard, je veux appeler

[self performSelector:@selector(mytest:withAString:) withObject: mystring];

dans MyClass.m, mais j'obtiens une erreur similaire à celle-ci * Terminer l'application en raison d'une exception non attrapée 'NSInvalidArgumentException', raison : '* -[MyClass myTest:withAtring :]: unrecognized selector sent to instance 0xe421f0' (Sélecteur non reconnu envoyé à l'instance 0xe421f0)

J'ai essayé un cas plus simple avec un sélecteur qui ne prenait pas d'arguments et qui imprimait une chaîne de caractères à la console et cela a bien fonctionné. Qu'est-ce qui ne va pas dans ce code et comment puis-je le corriger ? Merci.

315voto

Shane Arney Points 2775

En Objective-C, la signature d'un sélecteur est composée de :

  1. Le nom de la méthode (dans ce cas, ce serait 'myTest') (obligatoire)
  2. Un ':' (deux points) suivant le nom de la méthode si la méthode a une entrée.
  3. Un nom et ':' pour chaque entrée supplémentaire.

Les sélectionneurs n'en ont aucune connaissance :

  1. Les types d'entrée
  2. Le type de retour de la méthode.

Voici une implémentation de classe où la méthode performMethodsViaSelectors exécute les autres méthodes de la classe au moyen de sélecteurs :

@implementation ClassForSelectors
- (void) fooNoInputs {
    NSLog(@"Does nothing");
}
- (void) fooOneIput:(NSString*) first {
    NSLog(@"Logs %@", first);
}
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second {
    NSLog(@"Logs %@ then %@", first, second);
}
- (void) performMethodsViaSelectors {
    [self performSelector:@selector(fooNoInputs)];
    [self performSelector:@selector(fooOneInput:) withObject:@"first"];
    [self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second"];
}
@end

La méthode pour laquelle vous souhaitez créer un sélecteur n'a qu'une seule entrée. Vous devez donc créer un sélecteur pour cette méthode de la manière suivante :

SEL myTestSelector = @selector(myTest:);

138voto

Lyndsey Ferguson Points 3101

La signature de votre méthode est :

- (void) myTest:(NSString *)

withAString se trouve être le paramètre (le nom est trompeur, il semble qu'il fasse partie de la signature du sélecteur).

Si vous appelez la fonction de cette manière :

[self performSelector:@selector(myTest:) withObject:myString];

Ça va marcher.

Mais, comme les autres posters l'ont suggéré, vous pourriez vouloir renommer la méthode :

- (void)myTestWithAString:(NSString*)aString;

Et appelez :

[self performSelector:@selector(myTestWithAString:) withObject:myString];

14voto

Lirik Points 531

Shane Arney

performSelector:withObject:withObject:

Vous pourriez également mentionner que cette méthode ne permet de passer que 2 arguments maximum, et qu'elle ne peut pas être retardée. (comme performSelector:withObject:afterDelay:) .

C'est bizarre qu'apple ne supporte que 2 objets à envoyer et ne l'ait pas rendu plus générique.

7voto

Zack Points 806

Votre code a deux problèmes. L'un a été identifié et résolu, mais pas l'autre. Le premier est que le nom du paramètre de votre sélecteur est manquant. Cependant, même si vous corrigez ce problème, la ligne soulèvera toujours une exception, en supposant que la signature de votre méthode révisée inclut toujours plus d'un argument. Disons que votre méthode révisée est déclarée comme :

-(void)myTestWithString:(NSString *)sourceString comparedTo:(NSString *)testString ;

La création de sélecteurs pour les méthodes qui prennent plusieurs arguments est parfaitement valide (par exemple, @selector(myTestWithString:comparedTo :) ). Cependant, la méthode performSelector ne vous permet de passer qu'une seule valeur à myTest, qui a malheureusement plus d'un paramètre. Une erreur se produira et vous indiquera que vous n'avez pas fourni suffisamment de valeurs.

Vous pouvez toujours redéfinir votre méthode pour qu'elle prenne une collection comme seul paramètre :

-(void)myTestWithObjects:(NSDictionary *)testObjects ;

Cependant, il existe une solution plus élégante (qui ne nécessite pas de refactoring). La réponse est d'utiliser NSInvocation, ainsi que sa fonction setArgument:atIndex: y invoke méthodes.

J'ai écrit un article, comprenant un exemple de code si vous voulez plus de détails. L'accent est mis sur l'enfilage, mais les principes de base restent valables.

Bonne chance !

3voto

Rob Napier Points 92148

La signature de votre méthode n'a aucun sens, êtes-vous sûr qu'il ne s'agit pas d'une faute de frappe ? Je ne vois pas bien comment il compile, mais peut-être recevez-vous des avertissements que vous ignorez ?

Combien de paramètres cette méthode doit-elle prendre ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X