将Objective-C对象作为void*指针传递给函数

14

我有一个函数:

  myFunction (MyProc callback, void * ref)

这个函数是从Objective-C类内部调用的。函数将回调指针(类中的函数)和引用传递进去。由于回调是静态调用的,因此没有上下文,所以引用是必要的。可以使用引用来为回调提供上下文。

我想将Objective-C类作为引用传递。因此问题是:

如何将NSObject强制转换为void *,以及如何将void *强制转换为NSObject。

先行致谢。

3个回答

38

可以像这样做:

void func(void *q)
{
    NSObject* o = CFBridgingRelease(q);
    NSLog(@"%@", o);
}

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        NSObject* o = [NSObject new];
        func((void*)CFBridgingRetain(o));
    }
    return 0;
}
请注意,CFBridgingRetain()CFBridgingRelease()是编译器属性周围的宏。你可以随意使用其中任何一个。我喜欢API变体,因为它在我们的代码库中更常用,并且更明确 / 不容易混淆。 CFBridgingRetain()有效地强制保留对象,必须通过CFBridgingRelease()进行平衡。它还恰好返回一个与void*转换兼容的CFTypeRefCFBridgingRelease()则有效地撤消了这个强制保留,因此q仅在o有效的作用域内保持有效。 对于基本回调有效,但你可能不希望针对需要长时间保留的void* context;类型的内容进行操作。 对此,请参阅:
void callback(void *context)
{
    // grab an ARC aware reference without impacting hard-retain
    NSObject* o = (__bridge NSObject *)(context);
    NSLog(@"%@", o);
}

void freeContext(void *context)
{
    // release the hard-retain
    CFBridgingRelease(context);
}

请注意,如果您省略了强制类型转换或API调用,Xcode通常会很好地建议您应该做什么。它甚至解释了每个备选方案的含义(在我能够记住它们之前,我非常依赖这一点)。


9

我猜你正在使用ARC。在调用myFunction时,你可以像这样使用:

id ref = ...; // your Objective-C object
myFunction(callback, (__bridge_retained void *) ref);

在您的回调函数中,您必须将所有权归还:

void callback(void* refPtr) {
    id refObj = (__bridge_transfer id) refPtr;
}

请将id替换为适当的对象类型。


当我尝试将其转换为id时,它会显示:使用桥接传输强制转换,将void *转换为id时类型不兼容。 - James Andrews
我把我的 callback 函数放在我的测试项目中,跟我在这里发布的一模一样,但我没有看到任何编译错误。你可以试试看吗? - tia
1
如果回调将被调用多次,则不应使用__bridge_transfer,因为它会将所有权转移给ARC,对象将自动释放。 - jtbandes

1
答案:完全没有问题。 void * 隐式兼容任何指针类型,因此如果您有一个对象,它是类型为 id(别名为 struct objc_object *)的指针,则可以直接将其传递到需要 void 指针的位置,无需进行转换。例如:
// this is the declaration of the callback function:
void callback(void *context);

// then you can call it like this:
SomeClass *obj = [[SomeClass alloc] init];
callback(obj);

@BenSmiley 当你这样做时(什么?),然后呢? - user529758
1
当我进行桥接转换时,将void*转换回Objective-C对象时,会出现BAD_ACCESS异常。 - James Andrews
@BenSmiley 嗯。尝试暂时关闭 ARC,然后重试。那会做什么? - user529758
没有使用ARC也可以工作。但是我计划在这个项目中使用ARC。 - James Andrews
你的回答的第一行说void隐式兼容任何指针类型*。id是一个指针类型。在ARC下它与void*不兼容。因此,这个说法是不正确的。 - bbum
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接