@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_addMethodhere的文档。
如果您的 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() 获得的指针,但您不能传递它而不是选择器。