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

时间:2021-04-04 19:40:59

I have a function:

我有一个功能:

  myFunction (MyProc callback, void * ref)

This function is called from within an Objective-C class. The function is passed a pointer to the callback (a function in the class) and a reference. The reference is necessary because the callback is called statically and therefore doesn't have a context. The ref can be used to provide a context to the callback.

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

I want to be able to pass the Objective-C class as the reference. So the question is:

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

How do I cast an NSObject to a void * and how do I cast a void * as an NSObject.

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

Thanks in advance.

提前致谢。

3 个解决方案

#1


32  

Do something like this:

做这样的事情:

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;
}

Note that CFBridgingRetain() and CFBridgingRelease() are macros around compiler attributes. Feel free to use either. I like the API variant as it is in more common use in our codebases and it is more explicitly / less confusing.

请注意,CFBridgingRetain()和CFBridgingRelease()是围绕编译器属性的宏。随意使用。我喜欢API变体,因为它在我们的代码库中更常见,并且更明确/更少混淆。

CFBridgingRetain() effectively hard-retains the object that must be balanced by a CFBridgingRelease(). It also happens to return a CFTypeRef which is compatible with a cast to void*. CFBridgingRelease() effectively undoes that hard-retain and, thus, q will only remain valid within the scope that o is valid.

CFBridgingRetain()有效地硬保留必须由CFBridgingRelease()平衡的对象。它也恰好返回一个与转换为void *兼容的CFTypeRef。 CFBridgingRelease()有效地撤消了硬保留,因此q只会在o有效的范围内保持有效。

Valid for basic callbacks, but you'd probably not what that with a void *context; type thing that has to stick around for a while. For that:

适用于基本回调,但您可能不会使用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);
}

Note that Xcode is quite good about suggesting exactly what you should do if you leave out the cast / API call. It even explains the meanings of each of the alternative solutions (I relied on this heavily until I could keep 'em straight in my head).

请注意,如果省略cast / API调用,Xcode非常适合建议您应该做什么。它甚至解释了每种替代解决方案的含义(我依赖于这一点,直到我能够让他们直接进入我的脑海)。

#2


6  

I assume you are using ARC. You can use something like this when calling myFunction

我假设你正在使用ARC。调用myFunction时可以使用类似的东西

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

In your callback, you must transfer the ownership back:

在回调中,您必须转回所有权:

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

Replace id with your object type as appropriated.

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

#3


1  

Answer: in no way. void * is implicitly compatible with any pointer type, so if you have an object, which is a pointer of type id (alias for struct objc_object *), you can simply pass it where the void pointer is needed, without casting. Example:

答:绝不。 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);

#1


32  

Do something like this:

做这样的事情:

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;
}

Note that CFBridgingRetain() and CFBridgingRelease() are macros around compiler attributes. Feel free to use either. I like the API variant as it is in more common use in our codebases and it is more explicitly / less confusing.

请注意,CFBridgingRetain()和CFBridgingRelease()是围绕编译器属性的宏。随意使用。我喜欢API变体,因为它在我们的代码库中更常见,并且更明确/更少混淆。

CFBridgingRetain() effectively hard-retains the object that must be balanced by a CFBridgingRelease(). It also happens to return a CFTypeRef which is compatible with a cast to void*. CFBridgingRelease() effectively undoes that hard-retain and, thus, q will only remain valid within the scope that o is valid.

CFBridgingRetain()有效地硬保留必须由CFBridgingRelease()平衡的对象。它也恰好返回一个与转换为void *兼容的CFTypeRef。 CFBridgingRelease()有效地撤消了硬保留,因此q只会在o有效的范围内保持有效。

Valid for basic callbacks, but you'd probably not what that with a void *context; type thing that has to stick around for a while. For that:

适用于基本回调,但您可能不会使用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);
}

Note that Xcode is quite good about suggesting exactly what you should do if you leave out the cast / API call. It even explains the meanings of each of the alternative solutions (I relied on this heavily until I could keep 'em straight in my head).

请注意,如果省略cast / API调用,Xcode非常适合建议您应该做什么。它甚至解释了每种替代解决方案的含义(我依赖于这一点,直到我能够让他们直接进入我的脑海)。

#2


6  

I assume you are using ARC. You can use something like this when calling myFunction

我假设你正在使用ARC。调用myFunction时可以使用类似的东西

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

In your callback, you must transfer the ownership back:

在回调中,您必须转回所有权:

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

Replace id with your object type as appropriated.

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

#3


1  

Answer: in no way. void * is implicitly compatible with any pointer type, so if you have an object, which is a pointer of type id (alias for struct objc_object *), you can simply pass it where the void pointer is needed, without casting. Example:

答:绝不。 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);