我一直在寻找这个好几个小时。
好像以前没有被问过。
有谁知道如何将指向Objective-C方法的C函数指针转换为SEL
类型(@selector
)?
更新:
我只是在玩运行时:
Method method = class_getInstanceMethod([self class], @selector(test:));
IMP objectMethod = method_getImplementation(method);
objectMethod(self, @selector(<???>), [self superclass]);
我以某种方式开始记得从某处读到
SEL
(@selector
)只是一个指针。所以出于好奇,我想,如果我可以设置一个指向Objective-C方法的指针,我可以用这个指向函数的指针替换(SEL
)@selector()
,因为它们都是指针吗?
最佳答案
@selector
不是方法,它是一个选择器,它可以帮助Objective C运行时选择一个方法。 Objective C中的方法是具有至少两个参数的C函数,它们是必需的:id self
,它表示对象; SEL selector
,它表示用于调用该函数的选择器。如果使用更多参数定义了方法,则它们将紧随两个必需参数之后。此功能称为IMP
实现。每个Objective C方法都有一个后缀IMP
。IMP
的定义如下:
typedef id (*IMP)(id, SEL, ...);
如果您具有C函数,并且具有正确的参数布局,则可以将该函数分配给现有的或全新的方法,并作为实例或类方法添加到类中。如果您的C函数没有必需的参数布局,则说明正在崩溃。确保C函数正确。
因此,让我们假设使用C函数:
void func_name(id self, SEL sel, NSUInteger x)
{
NSLog(@"I was called on object %@ with selector %@ and argument %lu", self, NSStringFromSelector(sel), x);
}
并希望将其分配给
-[NSObject myNewMethodWithUnsignedInteger:]
,您可以使用运行时来这样做:class_addMethod([NSObject class], @selector(myNewMethodWithUnsignedInteger:), (IMP)func_name, [NSString stringWithFormat:@"v@:%s", @encode(NSUInteger)]);
确保阅读
class_addMethod
here的文档。如果您的C函数不是必需的格式,则可以使用
imp_implementationWithBlock
将函数的调用包装在一个块中。因此,假设您具有以下功能:
void nonCompliantFunc(NSUInteger x)
{
NSLog(@"Can't touch this!");
}
您可以像这样添加它:
IMP imp = imp_implementationWithBlock(^ (id self, NSUInteger x) { nonCompliantFunc(x); };
class_addMethod([NSObject class], @selector(myNewMethodWithUnsignedInteger:), imp, [NSString stringWithFormat:@"v@:%s", @encode(NSUInteger)]);
您应该检查
class_addMethod
的返回值,以确保成功添加了该方法。为了回答您的更新,选择器是指针,但它们是方法表中的指针。加载运行时时,将收集所有选择器,并构建一个表。然后,在加载每个类时,将建立一个方法表,配对选择器和实现。这要复杂得多,但这是要点。
您正在考虑的指针是使用
method_getImplementation()
获得的指针,但是您不能传递该指针而不是选择器。
关于ios - C功能指针到SEL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22570842/