Wie kann ich mit Objective-C zur Laufzeit dynamisch einen Selektor erstellen?


93

Ich weiß, wie man einen SELzur Kompilierungszeit mit erstellt, @selector(MyMethodName:)aber ich möchte einen Selektor dynamisch aus einem erstellen NSString. Ist das überhaupt möglich?

Was ich tun kann:

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

Was ich tun möchte: (Pseudocode, das funktioniert offensichtlich nicht)

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

Ich habe die Apple API-Dokumente durchsucht, aber keinen Weg gefunden, der nicht auf der @selector(myTarget:)Syntax zur Kompilierungszeit beruht .

Antworten:


180

Ich bin kein Objective-C-Programmierer, nur ein Sympathisant, aber vielleicht brauchen Sie NSSelectorFromString . In der Laufzeitreferenz wird explizit erwähnt, dass Sie damit eine Zeichenfolge in einen Selektor konvertieren können.


5
Ich muss mein Google-Fu auffrischen. Genau das habe ich gesucht (oder auch nicht).
Craigb

Nun, ich hatte immer noch die Links in meinen Lesezeichen, seit ich vor ein paar Tagen die Objective-C 2.0-Dokumente gelesen habe.
Torsten Marek

40

Laut der XCode-Dokumentation macht Ihr Pseudocode es im Grunde richtig.

Am effizientesten ist es, SEL-Variablen zur Kompilierungszeit mit der Direktive @selector () Werte zuzuweisen. In einigen Fällen muss ein Programm jedoch zur Laufzeit möglicherweise eine Zeichenfolge in einen Selektor konvertieren. Dies kann mit der Funktion NSSelectorFromString erfolgen:

setWidthHeight = NSSelectorFromString(aBuffer);

Edit: Schade, zu langsam. : P.


2
NSStringFromSelector(@"doWork")konvertiert es in die andere Richtung (nur zu
Ihrer Information

8
Ich denke du meinst, NSStringFromSelector (@selector (doWork))
jpswain

Und was macht dieser Selektor angeblich? Sollten wir nicht einen Block oder etwas angeben?
user4951

12

Ich muss sagen, dass es etwas komplizierter ist, als die Antworten der vorherigen Befragten vermuten lassen ... wenn Sie wirklich einen Selektor erstellen möchten ... nicht nur "einen anrufen", den Sie "herumliegen". .

Sie müssen einen Funktionszeiger erstellen, der von Ihrer "neuen" Methode aufgerufen wird. Für eine Methode wie würden [self theMethod:(id)methodArg];Sie also schreiben ...

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

und dann müssen Sie den IMPBlock dynamisch generieren , diesmal unter Übergabe von "self", the SELund allen Argumenten ...

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

und fügen Sie es Ihrer Klasse hinzu, zusammen mit einer genauen Methodensignatur für den gesamten Trottel (in diesem Fall "v@:@"void return, Objektaufrufer, Objektargument)

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

Sie können einige gute Beispiele für diese Art von Laufzeit-Spielereien in einem meiner Repos hier sehen.


5

Ich weiß, dass dies schon vor langer Zeit beantwortet wurde, aber ich möchte es trotzdem teilen. Dies kann auch mit erfolgen sel_registerName.

Der Beispielcode in der Frage kann folgendermaßen umgeschrieben werden:

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

2
Eigentlich verwendet NSSelectorFromStringvon @ torsten-marek sel_registerNameunter der Haube. appledev : "NSSelectorFromString übergibt eine UTF-8-codierte Zeichendarstellung von aSelectorName an sel_registerName und gibt den von dieser Funktion zurückgegebenen Wert zurück"
PLG
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.