Home > Articles > Programming > C/C++

  • Print
  • + Share This
This chapter is from the book

This chapter is from the book

Interoperating with C

In garbage collected mode, not all memory is scanned. Anything allocated by malloc() is invisible to the garbage collector. If you pass an object pointer as a void * parameter to a C function, which then stores it in malloc()’d memory, it becomes invisible to the collector and may be freed even though there are still references to it.

In ARC mode, the compiler will handle pointers that are on the stack or in instance variables for you automatically, but it won’t track pointers in structures or anything else explicitly declared as __unsafe_unretained.

Normally, you would send a -retain message to an object before storing it on the heap, but that does nothing in garbage collected mode and is forbidden in ARC mode. Instead, you have to use the CFRetain() function. This will increment the object’s reference count, irrespective of whether the collector is running. The collector will only free objects when their retain count is zero and it cannot find any references to them in traced memory.

When you have finished with a reference that is outside of the collector’s scope, you need to call CFRelease().

ARC provides a richer memory model for this kind of operation. Explicit casts from object to non-object pointer types are no longer allowed. They must be replaced by bridged casts. Consider the following bit of code in non-ARC mode:

void *aPointer = (void*)someObject;

In ARC mode, this would create an untracked pointer from a tracked pointer, which is not something that you want to do without thinking. You have three basic options. The first is most commonly used for on-stack variables, or variables pointing to objects that are guaranteed to be referenced elsewhere:

void *aPointer = (__bridge void*)someObject;

This performs the cast with no transfer of ownership. If all other references to someObject are dropped, then aPointer becomes a dangling pointer. If the void * pointer is going on the heap somewhere and should keep an owning reference to the object, then you should use a retained bridging cast:

void *aPointer = (__bridge_retained void*)
    someObject;

This will move a single owning reference out of ARC’s control. This is roughly equivalent to sending a -retain message to someObject before it is stored. If you write (__bridge_retained void *)someObject with no assignment, then this tells the compiler to retain the object. Doing this is considered very bad style. You should use the inverse operation when casting back to an object pointer:

id anotherObjectPointer = (__bridge_transfer
    id)aPointer;
aPointer = NULL;

This transfers an owning reference into ARC’s control. ARC is now responsible for releasing the object, so it is important to remember to zero the C pointer. If you are not taking ownership of the pointer, then you should use a simple __bridge cast.

  • + Share This
  • 🔖 Save To Your Account