【问题标题】:Creating an IMP from an Objective-C block从 Objective-C 块创建 IMP
【发布时间】:2010-12-20 19:20:56
【问题描述】:

据我所知,Objective-C 中的 IMP 类型代表一个函数指针。有什么方法可以从块指针中生成 IMP 吗?感谢您的想法。

【问题讨论】:

  • 我加了一堆标签; 'objective-c-runtime' 不是一个非常常用的标签,而且这个 [非常有趣的] 问题已经被淘汰了。
  • 但是,从块中获取 IMP 的目标是什么?

标签: objective-c cocoa osx-snow-leopard objective-c-blocks objective-c-runtime


【解决方案1】:

自编写以来,现在 iOS 和 Mac OS X 中的 API 允许将块直接转换为 IMP。我写了一个 weblog post 描述 API (imp_implementationWithBlock())。


块实际上是一个结构,其中包含一些元数据、对块中包含的代码的引用以及在块中捕获的 const 复制数据的副本。

因此,不,没有办法在 IMP 和块引用之间直接映射。

当对块的调用被编译时,编译器会发出一个蹦床来设置堆栈帧,然后跳转到块内的可执行代码。

不过,您可以做的是创建一个像蹦床一样工作的 IMP。对于以下内容,您将需要一个特定的 IMP 来调用每组参数和返回类型。如果您需要使其通用,则需要使用程序集。

为此,我为每个类的实例设置了唯一的块实例。如果你想有一个通用块作用于所有实例,构建一个 SEL 的哈希 -> 每个类的块。

(1) 使用关联引用机制关联块以充当 IMP。比如:

void (^implementingBlock)(id s, SEL _c, int v) = ^(id s, SEL _c, int v) {
     // do something here
}

objc_setAssociatedObject(obj, SELToImp, [implementingBlock copy]));

(2) 实现一个类似这样的蹦床 IMP:

void void_id_sel_intTramp(id self, SEL _cmd, int value) {
    int (^block)(id s, SEL _c, int v) = objc_getAssociatedObject(self, _cmd);
    block(self, _cmd, value);
}

(3) 通过 Objective-C 运行时的 API 将上述蹦床填充到任何选择器中(参见 method_setImplementation 等)

注意事项:

  • 这是在 StackOverflow 中输入的。真实的代码会相似,但可能略有不同。

  • [implementingBlock copy] 很关键;块在堆栈中开始生命(通常)

【讨论】:

  • 非常酷的解决方案,非常感谢!我会尝试一下。我最终使用了映射到选择器的块哈希,但我将它存储在 NSMutableDictionary 实例变量中。不过,我从没想过要使用objc_setAssociatedObject。太棒了。
  • 顺便问一下,你认为你可以详细说明整个组装的事情吗?我对此很着迷,但我真的不太了解它是如何运作的。
  • 在 iOS 4.3 和 Mac OS X 10.7 中,有 imp_implementationWithBlock(), but I think you already knew that
  • 是的——我应该据此重写这个答案。当我写这篇文章时,我 imp_implementationWithBlock() 是 NDA 的。
【解决方案2】:

我相信 Mike Ash 在 Landon Fuller 的帮助下已经解决了一般情况下的问题,包括 iOS,这更难。他在github 上有一个类,它将把一个块变成一个函数指针。

您可能还想授予announcement 和一些关于 cocoa-unbound 的有趣后续讨论。

更新:现在有上面提到的imp_implementationWithBlock()

【讨论】:

    猜你喜欢
    • 2012-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多