Is there a way to wrap an ObjectiveC block into function pointer?

前端 未结 4 1835
忘了有多久
忘了有多久 2020-12-10 05:51

I have to provide a C-style callback for a specific C library in an iOS app. The callback has no void *userData or something similar. So I am not able to loop i

4条回答
  •  清歌不尽
    2020-12-10 06:17

    Technically, you could get access to a function pointer for the block. But it's totally unsafe to do so, so I certainly don't recommend it. To see how, consider the following example:

    #import 
    
    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);
        }
    }
    

    Running that yields:

    Howdy 1
    ret = 1
    

    Which is what we'd expect from purely executing those blocks directly with block(). So, you could use invoke as your function pointer.

    But as I say, this is totally unsafe. Don't actually use this!

    If you want to see a write-up of a way to do what you're asking, then check this out: http://www.mikeash.com/pyblog/friday-qa-2010-02-12-trampolining-blocks-with-mutable-code.html

    It's just a great write-up of what you would need to do to get this to work. Sadly, it's never going to work on iOS though (since you need to mark a page as executable which you're not allowed to do within your app's sandbox). But nevertheless, a great article.

提交回复
热议问题