自编写以来,现在 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 等)
注意事项: