我有一个函数:
myFunction (MyProc callback, void * ref)
这个函数是从Objective-C类内部调用的。函数将回调指针(类中的函数)和引用传递进去。由于回调是静态调用的,因此没有上下文,所以引用是必要的。可以使用引用来为回调提供上下文。
我想将Objective-C类作为引用传递。因此问题是:
如何将NSObject强制转换为void *,以及如何将void *强制转换为NSObject。
先行致谢。
我有一个函数:
myFunction (MyProc callback, void * ref)
这个函数是从Objective-C类内部调用的。函数将回调指针(类中的函数)和引用传递进去。由于回调是静态调用的,因此没有上下文,所以引用是必要的。可以使用引用来为回调提供上下文。
我想将Objective-C类作为引用传递。因此问题是:
如何将NSObject强制转换为void *,以及如何将void *强制转换为NSObject。
先行致谢。
可以像这样做:
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*
转换兼容的CFTypeRef
。 CFBridgingRelease()
则有效地撤消了这个强制保留,因此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通常会很好地建议您应该做什么。它甚至解释了每个备选方案的含义(在我能够记住它们之前,我非常依赖这一点)。
我猜你正在使用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
替换为适当的对象类型。
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);
id
是一个指针类型。在ARC下它与void*
不兼容。因此,这个说法是不正确的。 - bbum
callback
函数放在我的测试项目中,跟我在这里发布的一模一样,但我没有看到任何编译错误。你可以试试看吗? - tia__bridge_transfer
,因为它会将所有权转移给ARC,对象将自动释放。 - jtbandes