I know how to create a SEL
at compile time using @selector(MyMethodName:)
but what I want to do is create a selector dynamically from an NSString
. Is this even possible?
What I can do:
SEL selector = @selector(doWork:);
[myobj respondsToSelector:selector];
What I want to do: (pseudo code, this obviously doesn't work)
SEL selector = selectorFromString(@"doWork");
[myobj respondsToSelector:selector];
I've been searching the Apple API docs, but haven't found a way that doesn't rely on the compile-time @selector(myTarget:)
syntax.
Dynamic binding is determining the method to invoke at runtime instead of at compile time. Dynamic binding is also referred to as late binding. In Objective-C, all methods are resolved dynamically at runtime. The exact code executed is determined by both the method name (the selector) and the receiving object.
In Objective-C, selector has two meanings. It can be used to refer simply to the name of a method when it's used in a source-code message to an object. It also, though, refers to the unique identifier that replaces the name when the source code is compiled. Compiled selectors are of type SEL .
In Swift, Objective-C selectors are represented by the Selector structure, and you create them using the #selector expression. In Swift, you create a selector for an Objective-C method by placing the name of the method within the #selector expression: #selector(MyViewController. tappedButton(_:)) .
I'm not an Objective-C programmer, merely a sympathizer, but maybe NSSelectorFromString is what you need. It's mentioned explicity in the Runtime Reference that you can use it to convert a string to a selector.
According to the XCode documentation, your psuedocode basically gets it right.
It’s most efficient to assign values to SEL variables at compile time with the @selector() directive. However, in some cases, a program may need to convert a character string to a selector at runtime. This can be done with the NSSelectorFromString function:
setWidthHeight = NSSelectorFromString(aBuffer);
Edit: Bummer, too slow. :P
I'd have to say that it's a little more complicated than the previous respondents' answers might suggest... if you indeed really want to create a selector... not just "call one" that you "have laying around"...
You need to create a function pointer that will be called by your "new" method.. so for a method like [self theMethod:(id)methodArg];
, you'd write...
void (^impBlock)(id,id) = ^(id _self, id methodArg) {
[_self doSomethingWith:methodArg];
};
and then you need to generate the IMP
block dynamically, this time, passing, "self", the SEL
, and any arguments...
void(*impFunct)(id, SEL, id) = (void*) imp_implementationWithBlock(impBlock);
and add it to your class, along with an accurate method signature for the whole sucker (in this case "v@:@"
, void return, object caller, object argument)
class_addMethod(self.class, @selector(theMethod:), (IMP)impFunct, "v@:@");
You can see some good examples of this kind of runtime shenanigans, in one of my repos, here.
I know this has been answered for long ago, but still I wanna share. This can be done using sel_registerName
too.
The example code in the question can be rewritten like this:
SEL selector = sel_registerName("doWork:");
[myobj respondsToSelector:selector];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With