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


93

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

我可以做什么:

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

我想做什么:(伪代码,这显然行不通)

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

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

Answers:


180

我不是Objective-C程序员,而是同情者,但也许您需要NSSelectorFromString。在运行时参考中明确提到,您可以使用它将字符串转换为选择器。


5
我需要复习我的Google-fu。那正是我一直在寻找(或者不是那样)的东西。
craigb

好吧,自从几天前阅读了Objective-C 2.0文档以来,我的书签中仍然链接不断。
Torsten Marek

40

根据XCode文档,您的psuedocode基本上可以正确处理它。

在编译时使用@selector()指令为SEL变量赋值是最有效的。但是,在某些情况下,程序可能需要在运行时将字符串转换为选择器。这可以通过NSSelectorFromString函数来完成:

setWidthHeight = NSSelectorFromString(aBuffer);

编辑:Bu,太慢了。:P


2
NSStringFromSelector(@"doWork")将其转换为另一种方式(仅供参考)
bentytree 2012年

8
我想你是说NSStringFromSelector(@selector(doWork))
jpswain 2012年

那个选择器应该做什么?我们不应该指定块或其他内容吗?
user4951 '11

12

我不得不说,比以前的回答者所建议的要复杂一些……如果您确实要创建一个选择器 ……而不仅仅是“打电话给您”已经放置的那个。 。

您需要创建一个函数指针,该指针将由您的“新”方法调用..因此对于类似的方法[self theMethod:(id)methodArg];,您需要编写...

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

然后您需要IMP动态生成块,这一次传递“ self” SEL,以及任何参数...

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

并将其以及整个吸盘的准确方法签名(在本例"v@:@"中为void return,对象调用者,对象参数)添加到您的类中

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

在我的一个回购中,您可以在这种运行时技巧上看到一些很好的例子


5

我知道这个问题早已得到解决,但我仍然想分享。这也可以使用完成sel_registerName

问题中的示例代码可以这样重写:

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

2
实际上,NSSelectorFromString@ torsten-marek提到的是sel_registerName在后台使用。appledev“ NSSelectorFromString将aSelectorName的UTF-8编码字符表示传递给sel_registerName并返回该函数返回的值”
PLG
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.