Comment créer dynamiquement un sélecteur lors de l'exécution avec Objective-C?


93

Je sais comment créer un SELau moment de la compilation en utilisant @selector(MyMethodName:)mais ce que je veux faire est de créer un sélecteur dynamiquement à partir d'un fichier NSString. Est-ce seulement possible?

Qu'est-ce que je peux faire:

SEL selector = @selector(doWork:);
[myobj respondsToSelector:selector];

Ce que je veux faire: (pseudo code, cela ne fonctionne évidemment pas)

SEL selector = selectorFromString(@"doWork");
[myobj respondsToSelector:selector];

J'ai cherché dans la documentation de l'API Apple, mais je n'ai pas trouvé de moyen qui ne repose pas sur la @selector(myTarget:)syntaxe de compilation .

Réponses:


180

Je ne suis pas un programmeur Objective-C, simplement un sympathisant, mais peut-être que NSSelectorFromString est ce dont vous avez besoin. Il est mentionné explicitement dans le Runtime Reference que vous pouvez l'utiliser pour convertir une chaîne en sélecteur.


5
J'ai besoin de rafraîchir mon Google-fu. c'est exactement ce que je cherchais (ou pas comme ça peut être).
craigb

Eh bien, j'avais toujours les liens dans mes signets depuis que j'ai lu la documentation Objective-C 2.0 il y a quelques jours.
Torsten Marek

40

Selon la documentation XCode, votre psuedocode fait les choses correctement.

Il est plus efficace d'attribuer des valeurs aux variables SEL au moment de la compilation avec la directive @selector (). Cependant, dans certains cas, un programme peut avoir besoin de convertir une chaîne de caractères en sélecteur lors de l'exécution. Cela peut être fait avec la fonction NSSelectorFromString:

setWidthHeight = NSSelectorFromString(aBuffer);

Edit: Bummer, trop lent. : P


2
NSStringFromSelector(@"doWork")le convertit dans l'autre sens (juste pour info)
bendytree

8
Je pense que vous voulez dire, NSStringFromSelector (@selector (doWork))
jpswain

Et que fait ce sélecteur? Ne devrions-nous pas spécifier un bloc ou quelque chose?
user4951

12

Je dois dire que c'est un peu plus compliqué que ce que les réponses des répondants précédents pourraient suggérer ... si vous voulez vraiment créer un sélecteur ... pas seulement "appeler un" que vous "avez traîner" .. .

Vous devez créer un pointeur de fonction qui sera appelé par votre "nouvelle" méthode .. donc pour une méthode comme [self theMethod:(id)methodArg];, vous écririez ...

void (^impBlock)(id,id) = ^(id _self, id methodArg) { 
     [_self doSomethingWith:methodArg]; 
};

et ensuite vous devez générer le IMPbloc dynamiquement, cette fois, en passant, "self", le SEL, et tous les arguments ...

void(*impFunct)(id, SEL, id) = (void*) imp_implementationWithBlock(impBlock);

et ajoutez-le à votre classe, avec une signature de méthode précise pour l'ensemble de la ventouse (dans ce cas "v@:@", retour vide, appelant d'objet, argument d'objet)

 class_addMethod(self.class, @selector(theMethod:), (IMP)impFunct, "v@:@");

Vous pouvez voir quelques bons exemples de ce genre de manigances d'exécution , dans l'un de mes dépôts, ici.


5

Je sais que cela a été répondu depuis longtemps, mais je veux toujours partager. Cela peut être fait en utilisant sel_registerNameaussi.

L'exemple de code dans la question peut être réécrit comme ceci:

SEL selector = sel_registerName("doWork:");
[myobj respondsToSelector:selector];

2
En fait, NSSelectorFromStringmentionné par @ torsten-marek utilise sel_registerNamesous le capot. appledev : "NSSelectorFromString transmet une représentation de caractère codé UTF-8 de aSelectorName à sel_registerName et renvoie la valeur renvoyée par cette fonction"
PLG
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.