Ios 指向SEL的C函数指针

Ios 指向SEL的C函数指针,ios,pointers,selector,objective-c-runtime,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(<???>

我已经找了好几个小时了

好像以前没人问过

有人知道如何将指向Objective-C方法的C函数指针转换为
SEL
类型(
@selector


更新:

我只是在玩运行时:

Method method = class_getInstanceMethod([self class], @selector(test:));
IMP objectMethod = method_getImplementation(method);
objectMethod(self, @selector(<???>), [self superclass]);
Method=class\u getInstanceMethod([self class],@selector(test:);
IMP objectMethod=方法\获取实现(方法);
objectMethod(self,@selector(),[self超类];

不知怎的,我开始记得从某个地方读到,
SEL
@selector
)只是一个指针。出于好奇,我想,如果我可以设置一个指向Objective-C方法的指针,我可以用这个指向函数的指针来替换(
SEL
@selector()
,因为它们都只是指针

@selector
不是一个方法,它是一个选择器,可以帮助Objective C运行时选择一个方法。目标C中的方法是至少具有两个参数的C函数,这两个参数是必需的:
id self
,它表示对象和
SEL selector
,它表示用于调用函数的选择器。如果该方法定义了更多参数,则它们位于两个必需参数之后。此函数称为
IMP
,实现。每个目标C方法都有一个支持
IMP

IMP
的定义如下:

typedef id (*IMP)(id, SEL, ...);
IMP imp = imp_implementationWithBlock(^ (id self, NSUInteger x) { nonCompliantFunc(x); };
class_addMethod([NSObject class], @selector(myNewMethodWithUnsignedInteger:), imp, [NSString stringWithFormat:@"v@:%s", @encode(NSUInteger)]);
如果您有一个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);
}
void nonCompliantFunc(NSUInteger x)
{
    NSLog(@"Can't touch this!");
}
如果要将其分配给
-[NSObject myNewMethodWithUnsignedInteger:
,则可以使用运行时执行此操作:

class_addMethod([NSObject class], @selector(myNewMethodWithUnsignedInteger:), (IMP)func_name, [NSString stringWithFormat:@"v@:%s", @encode(NSUInteger)]);
确保阅读
class\u addMethod
的文档

如果您的C函数不是所需的格式,您可以使用
imp_implementationWithBlock
将函数调用封装在块中

那么让我们假设您具有以下函数:

void func_name(id self, SEL sel, NSUInteger x)
{
    NSLog(@"I was called on object %@ with selector %@ and argument %lu", self, NSStringFromSelector(sel), x);
}
void nonCompliantFunc(NSUInteger x)
{
    NSLog(@"Can't touch this!");
}
您可以将其添加为如下所示的方法:

typedef id (*IMP)(id, SEL, ...);
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
的返回值,以确保方法添加成功


要回答您的更新,选择器是指针,但它们是方法表中的指针。加载运行时并生成表时,将收集所有选择器。然后,当加载每个类时,将设置一个方法表,将选择器和实现配对。这要复杂得多,但这是它的要点


您正在考虑的指针是使用
方法\u getImplementation()。目标C中的方法是至少具有两个参数的C函数,这两个参数是必需的:
id self
,它表示对象和
SEL selector
,它表示用于调用函数的选择器。如果该方法定义了更多参数,则它们位于两个必需参数之后。此函数称为
IMP
,实现。每个目标C方法都有一个支持
IMP

IMP
的定义如下:

typedef id (*IMP)(id, SEL, ...);
IMP imp = imp_implementationWithBlock(^ (id self, NSUInteger x) { nonCompliantFunc(x); };
class_addMethod([NSObject class], @selector(myNewMethodWithUnsignedInteger:), imp, [NSString stringWithFormat:@"v@:%s", @encode(NSUInteger)]);
如果您有一个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);
}
void nonCompliantFunc(NSUInteger x)
{
    NSLog(@"Can't touch this!");
}
如果要将其分配给
-[NSObject myNewMethodWithUnsignedInteger:
,则可以使用运行时执行此操作:

class_addMethod([NSObject class], @selector(myNewMethodWithUnsignedInteger:), (IMP)func_name, [NSString stringWithFormat:@"v@:%s", @encode(NSUInteger)]);
确保阅读
class\u addMethod
的文档

如果您的C函数不是所需的格式,您可以使用
imp_implementationWithBlock
将函数调用封装在块中

那么让我们假设您具有以下函数:

void func_name(id self, SEL sel, NSUInteger x)
{
    NSLog(@"I was called on object %@ with selector %@ and argument %lu", self, NSStringFromSelector(sel), x);
}
void nonCompliantFunc(NSUInteger x)
{
    NSLog(@"Can't touch this!");
}
您可以将其添加为如下所示的方法:

typedef id (*IMP)(id, SEL, ...);
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
的返回值,以确保方法添加成功


要回答您的更新,选择器是指针,但它们是方法表中的指针。加载运行时并生成表时,将收集所有选择器。然后,当加载每个类时,将设置一个方法表,将选择器和实现配对。这要复杂得多,但这是它的要点


您正在考虑的指针是使用
方法\u getImplementation()
获得的指针,但您不能传递该指针而不是选择器。

如何准确获得指针?方法_getName()是您要找的吗?@MartinR我会更新我的问题一点。@Unheilig请参阅更新我的答案。您到底是如何获得指针的?方法_getName()是你要找的吗?@MartinR我会更新一下我的问题。@Unheilig请看我答案的更新。我喜欢你提到不同场景的方式,其中一个描述了崩溃将如何出现+1.我会更新一下我的问题。我想你说的是
objc\u msgSend\u vtable
?除了记得从某个地方读到a
SEL
只是一个C指针之外,我总是恶作剧地认为C指针给了我们很多“控制”(在内存段中移动),因此我尝试了。此外,所以绝对没有办法用其他任何东西来取代
SEL
?谢谢。@Unheilig不,这很重要。您不能替换选择器,因为它们是选择正确implem的关键