Situation:
I need to pass an Objective-C object to an asynchronous C API as an opaque reference (void*) which will later be passed to the callback function I provide. The callback then calls a method on the object. The code needs to work in the presence of garbage collection, and the object must not be GC’d between my call to the C API and the time my callback is called by it.
The NSGarbageCollector class provides the disableCollectorForPointer: and enableCollectorForPointer: methods for marking and unmarking objects as uncollectable roots.
Question:
What I can’t work out from the docs and searching the web is if the calls to disableCollectorForPointer: are counted and must be balanced by the same number of enableCollectorForPointer: calls. If this is not the case and each object is either flagged as root or not, calling enableCollectorForPointer: in my callback might clear an existing root flag set by some other code, causing the object to be collected even though it shouldn’t!
The alternative I’ve seen is to use CFRetain and CFRelease – are these safe to use on my own NSObject subclasses? I’ve only used these functions on toll-free-bridged CF objects before.
Bonus points for answers which provide evidence. I see disableCollectorForPointer: recommended all over the place, with no mention of this safety aspect.
Notes:
- I have to support garbage collection as this code will be used by a PrefPane for System Preferences. The 64-bit version of a PrefPane must use garbage collection. So using ARC or manual refcounting is not an option.
- The C API is one of Apple’s (IOKit) so I have no control over it either.
I think I’ve found the answer. Source code for the garbage collector doesn’t seem to be available, but the header file declaring the interface for
NSGarbageCollector,NSGarbageCollector.hfrom theFoundation.frameworkcontains the following:Note the “stacking” comment – I assume this means that calls are indeed counted? More evidence still welcome!
Update:
Just to be really sure, I decided to test my hypothesis using a little test program (gcbridgetest.m):
Compiled with
gcc -fobjc-gc-only -g -Wall -Wextra -ObjC gcbridgetest.m -framework Foundation -o gcbridgetestand run as./gcbridgetest, it gives the following output, confirming that enable/disableCollectorForPointer: calls are indeed counted: