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

cra*_*igb 93 cocoa dynamic objective-c

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

我可以做什么:

SEL selector = @selector(doWork:);
[myobj respondsToSelector:selector];
Run Code Online (Sandbox Code Playgroud)

我想做什么:(伪代码,这显然不起作用)

SEL selector = selectorFromString(@"doWork");
[myobj respondsToSelector:selector];
Run Code Online (Sandbox Code Playgroud)

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

Tor*_*rek 180

我不是Objective-C程序员,只是一个同情者,但也许NSSelectorFromString是你需要的.它提到了运行时引用中的明确性,您可以使用它将字符串转换为选择器.

  • 我需要刷新我的Google-fu.这正是我所寻求的(或者不是它可能). (5认同)

Jos*_*non 41

根据XCode文档,您的伪代码基本上是正确的.

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

setWidthHeight = NSSelectorFromString(aBuffer);

编辑:糟糕,太慢了.:P

  • 我想你的意思是,NSStringFromSelector(@selector(doWork)) (8认同)
  • `NSStringFromSelector(@"doWork")`用另一种方式转换它(只是fyi) (2认同)

Ale*_*ray 11

我不得不说,比以前的受访者的答案可能暗示的要复杂得多......如果你确实想要创建一个选择器 ...而不只是"召唤一个"你"已经铺设"了...... .

你需要创建一个将由你的"新"方法调用的函数指针..所以对于像[self theMethod:(id)methodArg];你这样的方法你会写...

void (^impBlock)(id,id) = ^(id _self, id methodArg) { 
     [_self doSomethingWith:methodArg]; 
};
Run Code Online (Sandbox Code Playgroud)

然后你需要IMP动态生成块,这次,传递,"自我" SEL,和任何参数......

void(*impFunct)(id, SEL, id) = (void*) imp_implementationWithBlock(impBlock);
Run Code Online (Sandbox Code Playgroud)

并将它添加到您的类,以及整个吸盘的准确方法签名(在这种情况下"v@:@",void返回,对象调用者,对象参数)

 class_addMethod(self.class, @selector(theMethod:), (IMP)impFunct, "v@:@");
Run Code Online (Sandbox Code Playgroud)

你可以在我的一个repos中看到这种运行时恶作剧的一些很好的例子.


Kry*_*ton 5

我知道很久以前就已经回答了这个问题,但我仍然想分享。这也可以使用sel_registerName

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

SEL selector = sel_registerName("doWork:");
[myobj respondsToSelector:selector];
Run Code Online (Sandbox Code Playgroud)

  • 实际上,@torsten-marek 提到的“NSSelectorFromString” 在幕后使用了“sel_registerName”。[appledev](https://developer.apple.com/documentation/foundation/1395294-nsselectorfromstring?language=objc): _"NSSelectorFromString 将 aSelectorName 的 UTF-8 编码字符表示传递给 sel_registerName 并返回该函数返回的值“_ (2认同)