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

时间:2022-05-15 06:39:00

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?

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

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.

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

4 个解决方案

#1


179  

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.

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

#2


40  

According to the XCode documentation, your psuedocode basically gets it right.

根据XCode文档,您的psuedocode基本上是正确的。

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:

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

setWidthHeight = NSSelectorFromString(aBuffer);

setWidthHeight = NSSelectorFromString(在);

Edit: Bummer, too slow. :P

编辑:懒汉,太慢了。:P

#3


9  

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...

您需要创建一个函数指针,它将被您的“新”方法调用。所以对于像[self theMethod:(id)方法];

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...

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

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)

并将其添加到类中,并为整个sucker添加一个精确的方法签名(在本例中为“v@:@”、void return、对象调用者、对象参数)

 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.

在我的一个repos中,你可以看到这种运行时诡计的一些很好的例子。

#4


3  

I know this has been answered for long ago, but still I wanna share. This can be done using sel_registerName too.

我知道这已经被回答很久了,但我还是想分享。这也可以使用sel_registerName来完成。

The example code in the question can be rewritten like this:

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

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

#1


179  

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.

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

#2


40  

According to the XCode documentation, your psuedocode basically gets it right.

根据XCode文档,您的psuedocode基本上是正确的。

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:

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

setWidthHeight = NSSelectorFromString(aBuffer);

setWidthHeight = NSSelectorFromString(在);

Edit: Bummer, too slow. :P

编辑:懒汉,太慢了。:P

#3


9  

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...

您需要创建一个函数指针,它将被您的“新”方法调用。所以对于像[self theMethod:(id)方法];

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...

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

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)

并将其添加到类中,并为整个sucker添加一个精确的方法签名(在本例中为“v@:@”、void return、对象调用者、对象参数)

 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.

在我的一个repos中,你可以看到这种运行时诡计的一些很好的例子。

#4


3  

I know this has been answered for long ago, but still I wanna share. This can be done using sel_registerName too.

我知道这已经被回答很久了,但我还是想分享。这也可以使用sel_registerName来完成。

The example code in the question can be rewritten like this:

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

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