I'm wondering what are the recommended ways to handle situations where, in memory managed code, object didn't belong to any particular owner, i.e. objects released themselves. One such example could be a subclass of NSWindowController, which configures, displays and manages input and output of a single window. The controller object displays a window and releases itself later at some point (usually when the window or sheet it manages is closed). AppKit provides couple examples as well: NSAnimation retains itself in startAnimation and releases itself when the animation is done. Another example is NSWindow, which can be configured to release itself when closed.
When implementing these "self-owned" objects myself, I see at least three different GC-safe patterns, but all of them have some drawbacks.
a). Using CFRetain/CFRelease.
Self-owned object calls CFRetain on self before it starts its operation (e.g. in the window controller example before the window is displayed). It then calls CFRelease() on self when it's done (e.g. in the window controller example after the window is closed).
Pros: User of the object doesn't have to worry about memory management.
Cons: A bit ugly, since requires use of memory management functions, although we're using GC in pure ObjC code. If CFRelease() isn't called, leak may be hard to locate.
b). Avoiding self-ownership idiom with static data structure.
Object adds itself into a data structure (e.g. a static mutable array) before it starts its operation and removes itself from there when it's done.
Pros: User of the object doesn't have to worry about memory management. No calls to memory management functions. Objects have explicit owner. Potential leaks are easy to locate.
Cons: Locking is needed if objects may be created from different threads. Extra data structure.
c). Avoiding self-ownership idiom by requiring the user of object to save a reference to the object (e.g. into an ivar).
Pros: No calls to memory management functions. Objects have explicit owner.
Cons: User of the object has to keep a reference even if it doesn't need the object anymore. Extra ivars.
What pattern would you use to handle these cases?
For a), the more idiomatic alternative to CFRetain(foo)
/CFRelease(foo)
is [[NSGarbageCollector defaultCollector] disableCollectorForPointer:foo]
/[[NSGarbageCollector defaultCollector] enableCollectorForPointer:foo]
.
Apple's recommendation is (c), but I like the sound of (b). A static data structure allows you to hide the GC details from the API user while avoiding dipping into the CFRetain/CFRelease level. As you state, it also makes debugging and unit testing easier; if an object is still referenced by the static data structure after it's finished its task, you know there's a bug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With