简体   繁体   English

从Objective-C块创建IMP

[英]Creating an IMP from an Objective-C block

The IMP type in Objective-C represents a function pointer, as far I as understand. Objective-C中的IMP类型表示函数指针,据我所知。 Is there any way to make an IMP from a block pointer? 有没有办法从块指针创建IMP Thanks for your ideas. 谢谢你的想法。

Since this was written there is now API in iOS and Mac OS X that allows Blocks to be turned into IMPs directly. 由于这是编写的,现在iOS和Mac OS X中的API允许块直接转换为IMP。 I wrote up a weblog post describing the API (imp_implementationWithBlock()). 我写了一篇描述API的博客帖子 (imp_implementationWithBlock())。


A block is effectively a structure that contains a bit of metadata, a reference to the code contained within the block and a copy of the const-copied data captured within the block. 块实际上是包含一些元数据的结构,对块中包含的代码的引用以及块内捕获的const复制数据的副本。

Thus, no, there is no way to directly map between an IMP and a Block reference. 因此,不,没有办法在IMP和Block引用之间直接映射。

When a call to a block is compiled, the compiler emits a trampoline that sets up the stack frame and then jumps to the executable code within the block. 编译块调用时,编译器会发出一个设置堆栈帧的trampoline,然后跳转到块中的可执行代码。

What you can do, though, is create an IMP that acts like that trampoline. 但是,你可以做的是创建一个像蹦床一样的IMP。 For the following, you will need one specific IMP for each set of arguments & return types to be called. 对于以下内容,您将需要为每组参数和返回类型调用一个特定的IMP。 If you need to make this generic, you'll need to use assembly. 如果您需要使这个通用,您将需要使用程序集。

For this, I'm setting up unique block instances per instance of the class. 为此,我在每个类的实例中设置唯一的块实例。 If you want to have a generic block that acts across all instances, build a hash of SEL -> block per class. 如果您想拥有一个跨所有实例的通用块,请为每个类构建一个SEL - > block的哈希。

(1) Associate blocks to act as IMPs using the associated references mechanism. (1)使用关联的引用机制关联块以充当IMP。 Something like: 就像是:

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

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

(2) implement a trampoline IMP something like this: (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) stuff the above trampoline in for any selector via the Objective-C runtime's API (see method_setImplementation and like) (3)通过Objective-C运行时的API将上面的trampoline method_setImplementation任何选择器(参见method_setImplementation等)

Caveats: 注意事项:

  • this was typed into StackOverflow. 这被输入StackOverflow。 The real code will be similar, but likely slightly different. 真正的代码将类似,但可能略有不同。

  • the [implementingBlock copy] is critical; [implementationBlock copy]很关键; Blocks start life on the stack (usually) 块开始在堆栈上生活(通常)

I believe Mike Ash, with some help from Landon Fuller, has solved this for the general case, including iOS, which is harder. 我相信Mike Ash在Landon Fuller的帮助下已经解决了一般情况,包括iOS,这更难。 He has a class on github which will turn a block into a function pointer. 他在github上有一个类,它将块转换为函数指针。

You may also want to confer the announcement and some interesting follow-up discussion on cocoa-unbound. 您可能还想要发布关于cocoa-unbound的公告和一些有趣的后续讨论。

UPDATE: And now there's imp_implementationWithBlock() as referred above. 更新:现在有上面提到的imp_implementationWithBlock()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM