Come posso creare dinamicamente un selettore in fase di esecuzione con Objective-C?


93

So come creare un SELin fase di compilazione usando, @selector(MyMethodName:)ma quello che voglio fare è creare un selettore dinamicamente da un file NSString. È anche possibile?

Cosa posso fare:

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

Cosa voglio fare: (pseudo codice, questo ovviamente non funziona)

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

Ho cercato nei documenti dell'API di Apple, ma non ho trovato un modo che non si basi sulla @selector(myTarget:)sintassi in fase di compilazione .

Risposte:


180

Non sono un programmatore Objective-C, semplicemente un simpatizzante, ma forse NSSelectorFromString è ciò di cui hai bisogno. È menzionato esplicitamente nel Runtime Reference che puoi usarlo per convertire una stringa in un selettore.


5
Devo rispolverare il mio Google-fu. questo è esattamente quello che stavo (o non era come potrebbe essere) cercando.
Craigb

Bene, avevo ancora i link che volavano nei miei segnalibri da quando ho letto i documenti di Objective-C 2.0 un paio di giorni fa.
Torsten Marek,

40

Secondo la documentazione di XCode, il tuo psuedocode fondamentalmente lo fa bene.

È più efficiente assegnare valori alle variabili SEL in fase di compilazione con la direttiva @selector (). Tuttavia, in alcuni casi, un programma potrebbe dover convertire una stringa di caratteri in un selettore in fase di esecuzione. Questo può essere fatto con la funzione NSSelectorFromString:

setWidthHeight = NSSelectorFromString(aBuffer);

Modifica: peccato, troppo lento. : P


2
NSStringFromSelector(@"doWork")lo converte in un altro modo (solo per informazione)
bendytree

8
Penso che tu intenda, NSStringFromSelector (@selector (doWork))
jpswain

E cosa presumibilmente fa quel selettore? Non dovremmo specificare un blocco o qualcosa del genere?
user4951

12

Devo dire che è un po 'più complicato di quanto potrebbero suggerire le risposte degli intervistati precedenti ... se davvero vuoi davvero creare un selettore ... non solo "chiamane uno" che "hai in giro" .. .

Devi creare un puntatore a funzione che verrà chiamato dal tuo "nuovo" metodo .. quindi per un metodo come [self theMethod:(id)methodArg];, dovresti scrivere ...

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

e quindi devi generare il IMPblocco dinamicamente, questa volta passando, "self", il SEL, e qualsiasi argomento ...

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

e aggiungilo alla tua classe, insieme a una firma del metodo accurata per l'intero pollone (in questo caso "v@:@", void return, object caller, object argument)

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

Puoi vedere alcuni buoni esempi di questo tipo di imbrogli di runtime , in uno dei miei repository, qui.


5

So che è stata data una risposta molto tempo fa, ma voglio comunque condividere. Anche questo può essere fatto usando sel_registerName.

Il codice di esempio nella domanda può essere riscritto in questo modo:

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

2
In realtà, NSSelectorFromStringmenzionato da @ torsten-marek usa sel_registerNamesotto il cofano. appledev : "NSSelectorFromString passa una rappresentazione in caratteri codificati UTF-8 di aSelectorName a sel_registerName e restituisce il valore restituito da quella funzione"
PLG
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.