【问题标题】:C Function Pointer to SEL指向 SEL 的 C 函数指针
【发布时间】:2014-03-21 22:46:26
【问题描述】:

我已经找了好几个小时了。

好像以前没问过。

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

【问题讨论】:

  • 指针究竟是如何获取的? method_getName() 是你要找的吗?
  • @MartinR 我会稍微更新一下我的问题。
  • @Unheilig 查看我的答案的更新。

标签: ios pointers selector objective-c-runtime


【解决方案1】:

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

【讨论】:

  • 我喜欢你提到不同场景的方式,其中一个描述了崩溃是如何浮出水面的。 +1。我会稍微更新一下我的问题。
  • 我猜你说的是objc_msgSend_vtable?除了记得从某个地方读到 SEL 只是一个 C 指针之外,我总是恶作剧地认为 C 指针给了我们很多“控制”(在内存部分移动),因此尝试。另外,所以绝对没有办法用其他东西替换SEL?谢谢。
  • @Unheilig 不,那是different。您不能替换选择器,因为它们是选择正确实现的关键。
  • 查看this 答案以获取更多信息。
  • 这看起来很有趣(尽管我之前已经阅读过最后一个链接 ;-)。肯定会读另一本。接受您的综合回答。非常感谢:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
  • 2018-04-19
  • 1970-01-01
相关资源
最近更新 更多