Memory management tips under Garbage Collection
The CFRelease
function
Good old-fashioned reference counting (with retain
and release
) has been thrown out the window in the brave new Garbage Collected world.
Core Foundation objects are Garbage Collected too, but they continue to use a reference counting layer on top of the GC. This means that a CF object will only become eligible for collection when its reference count hits zero.
This makes CF objects great candidates for passing to sheet methods and the like which take void *
"context info" pointers. A normal Cocoa object might be collected here because the pointer to void is not considered a strong reference, but a CF object will remain in memory. When you get back from the sheet you can do a CFRelease
and the object will eventually be disposed of.
(Your alternative if you don’t want to directly touch anything CF is to use the disableCollectorForPointer:
and enableCollectorForPointer:
methods of the NSGarbageCollector
class, but that might end up being a bit more typing in many cases, unless you want to add some convenience methods to NSObject
via a category to do the same.)
One caveat: you’re not supposed to pass NULL
references to CFRelease
.
The CFMakeCollectable
function
To save you from this potentially error-prone pattern:
CFTypeRef thing = CFCreateSomething(...);
... do lots of stuff ...
CFRelease(thing); // ... at least, if you remember!
Apple provides CFMakeCollectable
:
CFTypeRef thing = CFMakeCollectable(CFCreateSomething(...));
... do lots of stuff ...
CFMakeCollectable
does a CFRelease
for you immediately and hands the reference back to you. The object sticks around because there is a strong reference to it (until the reference falls out of scope) but you don’t have to worry about remembering to CFRelease
it later on when you’re done with it.
The caveat: because CFMakeCollectable
is a wrapper for CFRelease
you must not pass NULL
references to it. This makes it unsuitable for use with some functions that may return NULL on failure, unless you test for NULL
first in which case you may as well just use CFRelease
anyway because it’s easier to type even if a little misleading about when the released object might end up getting deallocated ("release" sounds too immediate given that the object will stick around at least as long as there are strong references to it).
There is nothing to stop you from writing your own wrapper functions which check for NULL
references prior to calling CFRelease
or CFMakeCollectable
.
The NSMakeCollectable
function
The user-friendliest of them all because it is both NULL
-safe and does a cast to id
for you at the same time as marking something as collectable. When you do this:
NSString *string = NSMakeCollectable(CFTryToCreateThing(...));
It is equivalent to writing:
CFStringRef ref = CFTryToCreateThing(...);
if (ref)
CFRelease(ref);
NSString *string = (NSString *)ref;