据我所知,Objective-C 中的
IMP
类型代表函数指针。有什么方法可以从块指针创建 IMP
吗?谢谢你的想法。
自从编写此文以来,iOS 和 Mac OS X 中现在有 API 允许将 Block 直接转换为 IMP。我写了一篇博客文章描述 API (imp_implementationWithBlock())。
IMP imp = imp_implementationWithBlock(^(id _self) {
// do something here
});
class_addMethod(obj.class, SELToImp, imp, "v@:");
块实际上是一种结构,其中包含一些元数据、对块内包含的代码的引用以及块内捕获的常量复制数据的副本。
因此,不,无法在
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 中。真实的代码会类似,但可能略有不同。
【实现块复制】至关重要;块在堆栈上开始生命(通常)