objc_msgSend()用C回调函数作为代码块的参数?

时间:2013-02-11 09:24:32

标签: objective-c c core-foundation objective-c-runtime exc-bad-access

所以我试图调用一个Objective-C方法,该方法有一个回调代码块作为参数。

Objective-C方法(为了帖子的目的而实施)

- (void)requestWithCompletionHandler:(void(^)(BOOL, NSArray*))completionHandler {

    // Implementation ...

    completionHandler(YES, NSArray...);

}

C代码( rsc 包含分配和启动的类)

void callback(id self, SEL _cmd, BOOL success, CFArrayRef array)
{
    printf("BOOM\n");
}

objc_msgSend(rsc, sel_getUid("requestWithCompletionHandler:"), (IMP)callback);

来自Apple文档

id objc_msgSend(id theReceiver, SEL theSelector, ...)

也...

  

Objective-C方法只是一个至少需要两个的C函数   arguments-self和_cmd。例如,给定以下功能:

void myMethodIMP(id self, SEL _cmd)
{
    // implementation ....
}
  

你可以动态地将它作为方法(称为resolveThisMethodDynamically)添加到类中,如下所示:

class_addMethod([self class], @selector(resolveThisMethodDynamically), (IMP) myMethodIMP, "v@:");

然而,在运行时,我得到 EXC_BAD_ACCESS

2 个答案:

答案 0 :(得分:1)

有趣的是,它比我初想的容易。您只需传递一个实际的代码块作为参数。

objc_msgSend((id)rsc, sel_getUid("requestWithCompletionHandler:"), ^(BOOL success, CFArrayRef array) {
        if (success) {
            printf("BOOM\n");
        }});

答案 1 :(得分:1)

您将函数指针作为块类型的参数传递,但块不是函数指针。举个简单的例子,下面的代码将在takesABlock()的第二次调用时崩溃。

#include <stdio.h>
#include <dispatch/dispatch.h>

void function1();
void takesABlock(dispatch_block_t block);

int main(int argc, const char * argv[])
{

    dispatch_block_t block = ^{ printf("In a block\n"); function1(); };
    takesABlock(block);
    takesABlock((dispatch_block_t)function1);
}

void function1() {
    printf("In function1\n");
}

void takesABlock(dispatch_block_t block) {
    block();
}

所以,你需要传递一个实际的块:

objc_msgSend(rsc, sel_getUid("requestWithCompletionHandler:"), ^(BOOL aBool, NSArray *anArray){ // block code here });

看起来你正在做一些高度动态的事情,所以你可能需要找到一种方法来动态地将块存储在某个地方供以后使用。它是一个对象,可以通过使用-copy方法在Objective-C中复制,存储在集合等中,或者通过使用Block_copy()函数来获取指向堆的指针 - 在纯C API中分配块供以后使用。