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

时间:2012-10-16 14:06:17

标签: objective-c pointers casting callback

我有一个功能:

  myFunction (MyProc callback, void * ref)

从Objective-C类中调用此函数。该函数传递一个指向回调(类中的函数)和引用的指针。引用是必要的,因为回调是静态调用的,因此没有上下文。 ref可用于为回调提供上下文。

我希望能够传递Objective-C类作为参考。所以问题是:

如何将NSObject转换为void *以及如何将void *作为NSObject转换。

提前致谢。

3 个答案:

答案 0 :(得分:33)

做这样的事情:

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()平衡的对象。它也恰好返回一个CFTypeRef 与强制转换为void*兼容。 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);
}

请注意,如果省略cast / API调用,Xcode非常适合建议您应该做什么。它甚至可以解释每种替代解决方案的含义(我依赖这个解决方案,直到我能够将它们直接放在我的脑海中)。

答案 1 :(得分:7)

我假设您正在使用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替换为适当的对象类型。

答案 2 :(得分: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);