有没有办法将ObjectiveC块包装成函数指针?

Jan*_*ard 9 c objective-c callback ios objective-c-blocks

我必须为iOS应用中的特定C库提供C风格的回调.回调没有void *userData或类似的东西.所以我无法在上下文中循环.我想避免引入全局背景来解决这个问题.一个理想的解决方案是Objective-C块.

我的问题:有没有办法将一个块"转换"成一个函数指针或以某种方式包装/隐藏它?

mat*_*way 7

从技术上讲,您可以访问块的函数指针.但这样做完全不安全,所以我当然不推荐它.要了解具体方法,请考虑以下示例:

#import <Foundation/Foundation.h>

struct Block_layout {
    void *isa;
    int flags;
    int reserved; 
    void (*invoke)(void *, ...);
    struct Block_descriptor *descriptor;
};

int main(int argc, char *argv[]) {
    @autoreleasepool {
        // Block that doesn't take or return anything
        void(^block)() = ^{
            NSLog(@"Howdy %i", argc);
        };

        // Cast to a struct with the same memory layout
        struct Block_layout *blockStr = (struct Block_layout *)(__bridge void *)block;

        // Now do same as `block()':
        blockStr->invoke(blockStr);




        // Block that takes an int and returns an int
        int(^returnBlock)(int) = ^int(int a){
            return a;
        };

        // Cast to a struct with the same memory layout
        struct Block_layout *blockStr2 = (struct Block_layout *)(__bridge void *)returnBlock;

        // Now do same as `returnBlock(argc)':
        int ret = ((int(*)(void*, int a, ...))(blockStr2->invoke))(blockStr2, argc);
        NSLog(@"ret = %i", ret);
    }
}
Run Code Online (Sandbox Code Playgroud)

运行产生:

Howdy 1
ret = 1
Run Code Online (Sandbox Code Playgroud)

这是我们对直接执行这些块的期望block().因此,您可以将其invoke用作函数指针.

但正如我所说,这完全不安全.实际上不要用这个!

如果你想看到一种方法来表达你所要求的,那么请查看:http: //www.mikeash.com/pyblog/friday-qa-2010-02-12-trampolining-blocks -with-可变-code.html

这只是对你需要做些什么才能让它发挥作用的一个很好的记录.遗憾的是,它永远不会在iOS上工作(因为你需要将页面标记为可执行文件,而你的应用程序的沙箱中不允许这样做).但是,一篇很棒的文章.