MABlockClosure 0.0.1

MABlockClosure 0.0.1

测试已测试
语言语言 Obj-CObjective C
许可证 BSD
发布最新发布2014 年 12 月

未声明的拥有者 维护。



  • Mike Ash

MABlockClosure 使用 libffi 生成封装 Objective-C blocks 的函数指针。它将生成具有相同参数和返回类型的函数指针,当被调用时,将调用 block。Mac OS X 完全支持,也提供了对 iOS 的实验性支持。

MABlockClosure 以 BSD 许可证发布。关于官方许可证,请参阅 LICENSE 文件。

快速开始

使用代码的最简单方法是使用 BlockFptr 便利函数。这个函数返回一个函数指针,其生命周期与传递给它的 block 等同。请注意,block 必须位于堆或全局:栈块在超出作用域时将无法正确销毁函数指针。

带回调的示例

atexit(BlockFptr(^{ ...do something, no captured variables so it's a global block... }));

使用 block 为 NSObject 添加新方法

int captured = 42;
id block = ^(id self, SEL _cmd) { NSLog(@"captured is %d", captured); };
block = [block copy];
class_addMethod([NSObject class], @selector(my_printCaptured), BlockFptr(block));

为了更多控制返回的函数指针的生命周期,可以使用 MABlockClosure 类。当 MABlockClosure 对象被销毁时,它从 -fptr 方法提供的函数指针也将被销毁。

兼容性

由于 MABlockClosure 使用 libffi 执行所有繁重的操作,因此应该适用于任何提供 libffi 的处理器架构。

块与 libffi 之间的接口取决于块签名元数据的存在。此元数据是在使用与最新 Xcode 一起提供的 clang 构建编译时生成的。使用目前提供的 gcc 构建时不会生成此元数据。如果没有此元数据,代码将会很快且明显地失败。

块签名元数据与 Objective-C 方法签名字符串的格式相同。解析这些字符串很复杂。代码将解析由 @encode 语法支持的每个原始类型以及 NSRect、NSPoint、NSSize 及其 CG 等效类型。其他结构可以相对容易地添加,但这是一个手动过程,因为代码不会真正解析结构。

标准的 libffi 闭包需要在数据页上调用 mprotect 标记为可执行。目前不支持 iOS,因此它们在那里不起作用。Landon Fuller 开发了一个 libffi 的分支,使用一些非常脏的技巧来解决这个问题,并且 MABlockClosure 可以与这个分支一起工作。这需要构建自定义的 libffi,但 iOS 甚至不提供 libffi,所以无论如何都这样做。

iOS 支持

由于 iOS 不支持创建可执行数据,标准的 libffi 闭包在那里不起作用。Landon Fuller 开发了一个 libffi 的分支,使用一些非常脏的技巧来解决这个问题,并且 MABlockClosure 可以与这个分支一起工作。这需要构建自定义的 libffi,但 iOS 甚至不提供 libffi,所以无论如何都这样做。

请注意,iOS 上的 libffi 封闭项处于高度实验状态,您应谨慎处理。到目前为止,它们在有限的测试中表现良好,但请做好遇到麻烦的准备。

此 libffi 分支位于此处

http://github.com/landonf/libffi-ios

以下是关于如何使用 MABlockClosure 将此分支设置好并运行的简要说明。

首先,将 libffi-ios 仓库检出到您的项目文件夹旁边

git clone http://github.com/landonf/libffi-ios.git

接下来,使用 build-ios.sh 脚本来配置和构建它,使用正确的标志。(注意,您可能需要先编辑此脚本中的 SDK 设置。)

cd libffi-ios
./build-ios.sh

现在一切应该都已经构建完毕。然后您需要告诉您的 Xcode 项目如何找到这些文件夹。

您需要对项目设置进行两个更改。

首先,将以下内容添加到其他链接器标志

../libffi-ios/build-ios/.libs/libffi.a

接下来,将以下内容添加到头文件搜索路径

../libffi-ios/build-ios/include

最后,将 MABlockClosure 文件添加到您的项目中。现在您应该在 iOS 上能够使用 MABlockClosure。