我一直在寻找这个好几个小时。
以前似乎没有问过它。
有谁知道如何将指向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()
,因为它们都只是指针吗?
答案 0 :(得分:4)
@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()
获得的指针,但您无法传递而不是选择器。