Come posso creare dinamicamente un selettore in fase di esecuzione con Objective-C?
-
02-07-2019 - |
Domanda
So come creare un SEL
in fase di compilazione usando @selector (MyMethodName :)
ma quello che voglio fare è creare un selettore in modo dinamico da un NSString
. È anche possibile?
Cosa posso fare:
SEL selector = @selector(doWork:);
[myobj respondsToSelector:selector];
Cosa voglio fare: (codice pseudo, ovviamente non funziona)
SEL selector = selectorFromString(@"doWork");
[myobj respondsToSelector:selector];
Ho cercato i documenti dell'API di Apple, ma non ho trovato un modo che non si basi sulla sintassi @selector (myTarget :)
in fase di compilazione.
Soluzione
Non sono un programmatore di Objective-C, ma solo un simpatizzante, ma forse NSSelectorFromString è ciò di cui hai bisogno. È menzionato esplicitamente nella Riferimento runtime che puoi utilizzare per convertire una stringa in un selettore.
Altri suggerimenti
Secondo la documentazione di XCode, il tuo psuedocode praticamente funziona correttamente.
È 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: Bummer, troppo lento. : P
Dovrei 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 "messo 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 è necessario generare dinamicamente il blocco IMP
, questa volta, passando, " self " ;, SEL
e tutti gli argomenti ...
void(*impFunct)(id, SEL, id) = (void*) imp_implementationWithBlock(impBlock);
e aggiungilo alla tua classe, insieme a un'accurata firma del metodo per tutto il pollone (in questo caso " v @: @ "
, ritorno vuoto, chiamante oggetto, argomento oggetto)
class_addMethod(self.class, @selector(theMethod:), (IMP)impFunct, "v@:@");
Puoi vedere alcuni buoni esempi di questo tipo di shenanigans di runtime , in uno dei miei repository, qui.
So che questa è una risposta da molto tempo, ma voglio ancora condividerla. Questo può essere fatto anche usando sel_registerName
.
Il codice di esempio nella domanda può essere riscritto in questo modo:
SEL selector = sel_registerName("doWork:");
[myobj respondsToSelector:selector];