C SEL的功能指针

时间:2014-03-21 22:46:27

标签: ios pointers selector objective-c-runtime

我一直在寻找这个好几个小时。

以前似乎没有问过它。

有谁知道如何将指向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(),因为它们都只是指针吗?

1 个答案:

答案 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()获得的指针,但您无法传递而不是选择器。