如何使用 Objective-C 在运行时动态创建选择器?

我知道如何在编译时使用 @selector(MyMethodName:)创建 SEL,但我想做的是从 NSString动态创建一个选择器。这有可能吗?

我能做的:

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

我想做的: (伪代码,这显然不工作)

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

我一直在搜索 AppleAPI 文档,但没有找到一种不依赖于编译时 @selector(myTarget:)语法的方法。

48255 次浏览

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];