Je suis encore un peu novice en Objective-C et je me demande quelle est la différence entre les deux instructions suivantes ?
[object performSelector:@selector(doSomething)];
[object doSomething];
Je suis encore un peu novice en Objective-C et je me demande quelle est la différence entre les deux instructions suivantes ?
[object performSelector:@selector(doSomething)];
[object doSomething];
Fondamentalement, performSelector vous permet de déterminer dynamiquement le sélecteur à appeler sur l'objet donné. En d'autres termes, le sélecteur ne doit pas être déterminé avant l'exécution.
Ainsi, même si elles sont équivalentes :
[anObject aMethod];
[anObject performSelector:@selector(aMethod)];
Le deuxième formulaire vous permet de le faire :
SEL aSelector = findTheAppropriateSelectorForTheCurrentSituation();
[anObject performSelector: aSelector];
avant d'envoyer le message.
Pour cet exemple très basique dans la question,
[object doSomething];
[object performSelector:@selector(doSomething)];
il n'y a aucune différence dans ce qui va se passer. doSomething sera exécuté de manière synchrone par l'objet. Seulement "doSomething" est une méthode très simple, qui ne renvoie rien et ne nécessite aucun paramètre.
était-ce quelque chose d'un peu plus compliqué, comme :
(void)doSomethingWithMyAge:(NSUInteger)age;
les choses se compliqueraient, car [objet doSomethingWithMyAge:42] ;
ne peut plus être appelé avec une quelconque variante de "performSelector", car toutes les variantes avec paramètres n'acceptent que des paramètres d'objet.
Le sélecteur ici serait "doSomethingWithMyAge :" mais toute tentative de
[object performSelector:@selector(doSomethingWithMyAge:) withObject:42];
ne compilera tout simplement pas. Passer un NSNumber : @(42) au lieu de 42, n'aiderait pas non plus, car la méthode attend un type C de base - pas un objet.
En outre, il existe des variantes de performSelector jusqu'à 2 paramètres, pas plus. Alors que les méthodes ont souvent beaucoup plus de paramètres.
J'ai découvert que, bien que les variantes synchrones de performSelector :
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
renvoie toujours un objet, j'ai pu aussi renvoyer un simple BOOL ou NSUInteger, et ça a marché.
L'une des deux principales utilisations de performSelector est de composer dynamiquement le nom de la méthode que vous voulez exécuter, comme expliqué dans une réponse précédente. Par exemple
SEL method = NSSelectorFromString([NSString stringWithFormat:@"doSomethingWithMy%@:", @"Age");
[object performSelector:method];
L'autre utilisation consiste à envoyer de manière asynchrone un message à un objet qui sera exécuté plus tard dans la boucle d'exécution en cours. Pour cela, il existe plusieurs autres variantes de performSelector.
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
- (void)performSelector:(SEL)aSelector target:(id)target argument:(id)arg order:(NSUInteger)order modes:(NSArray *)modes;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg;
(oui, je les ai rassemblés à partir de plusieurs catégories de classes de la Fondation, comme NSThread, NSRunLoop et NSObject).
Chacune des variantes a un comportement particulier, mais toutes ont quelque chose en commun (du moins lorsque waitUntilDone est réglé sur NO). L'appel "performSelector" retournera immédiatement, et le message à l'objet ne sera placé sur le runloop actuel qu'après un certain temps.
En raison de l'exécution différée, aucune valeur de retour n'est naturellement disponible pour la méthode du sélecteur, d'où la valeur de retour -(void) dans toutes ces variantes asynchrones.
J'espère avoir couvert ce point d'une manière ou d'une autre...
@ennuikiller a raison. En fait, les sélecteurs générés dynamiquement sont utiles lorsque vous ne connaissez pas (et ne pouvez généralement pas connaître) le nom de la méthode que vous allez appeler lorsque vous compilez le code.
Une différence essentielle est que -performSelector:
et ses amis (y compris le Variantes multithread et retardées ) sont quelque peu limités dans la mesure où ils sont conçus pour être utilisés avec des méthodes comportant 0 à 2 paramètres. Par exemple, l'appel à -outlineView:toolTipForCell:rect:tableColumn:item:mouseLocation:
avec 6 paramètres et renvoyant le NSString
est assez difficile à manier et n'est pas supporté par les méthodes fournies.
Les sélecteurs sont un peu comme les pointeurs de fonction dans d'autres langages. Vous les utilisez lorsque vous ne savez pas, au moment de la compilation, quelle méthode vous voulez appeler au moment de l'exécution. De plus, comme les pointeurs de fonction, ils n'encapsulent que la partie verbale de l'invocation. Si la méthode possède des paramètres, vous devrez également les transmettre.
Un site NSInvocation
sert un objectif similaire, sauf qu'il lie ensemble plus d'informations. Non seulement il inclut la partie verbale, mais il inclut également l'objet cible et les paramètres. C'est utile lorsque vous voulez appeler une méthode sur un objet particulier avec des paramètres particuliers, non pas maintenant mais dans le futur. Vous pouvez construire un NSInvocation
et le virer plus tard.
Il existe une autre différence subtile entre les deux.
[object doSomething]; // is executed right away
[object performSelector:@selector(doSomething)]; // gets executed at the next runloop
Voici l'extrait de la documentation Apple
"performSelector:withObject:afterDelay : Exécute le sélecteur spécifié sur le fil d'exécution actuel au cours du prochain cycle de la boucle d'exécution et après un délai facultatif. Parce qu'elles attendent le prochain cycle de la boucle d'exécution pour exécuter le sélecteur, ces méthodes fournissent un mini retard automatique par rapport au code en cours d'exécution. Les sélecteurs multiples mis en file d'attente sont exécutés les uns après les autres dans l'ordre où ils ont été mis en file d'attente."
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.