Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass an Objective-C object to a function as a void * pointer

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.

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

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

Thanks in advance.

like image 278
James Andrews Avatar asked Oct 16 '12 14:10

James Andrews


People also ask

What is a void * in C?

The void pointer in C is a pointer that is not associated with any data types. It points to some data location in the storage. This means that it points to the address of variables. It is also called the general purpose pointer. In C, malloc() and calloc() functions return void * or generic pointers.

Can pointer point to void?

A void pointer is a pointer that can point to any type of object, but does not know what type of object it points to. A void pointer must be explicitly cast into another type of pointer to perform indirection. A null pointer is a pointer that does not point to an address. A void pointer can be a null pointer.

What does @() mean in Objective C?

It's Shorthand writing. In Objective-C, any character , numeric or boolean literal prefixed with the '@' character will evaluate to a pointer to an NSNumber object (In this case), initialized with that value. C's type suffixes may be used to control the size of numeric literals.

What does void mean in Objective C?

The (void) indicates the return type. This method doesn't return anything, so its result can't be assigned to anything.


1 Answers

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() 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.

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 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).

like image 58
bbum Avatar answered Sep 22 '22 15:09

bbum