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.
Related
I often use simple non compile-time immutable objects: like an array #[#"a", #"b"] or a dictionary #{#"a": #"b"}.
I struggle between reallocating them all the time:
- (void)doSomeStuff {
NSArray<NSString *> *fileTypes = #[#"h", #"m"];
// use fileTypes
}
And allocating them once:
- (void)doSomeStuff {
static NSArray<NSString *> * fileTypes;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
fileTypes = #[#"h", #"m"];
});
// use fileTypes
}
Are there recommendations on when to use each construct? Like:
depending on the size of the allocated object
depending on the frequency of the allocation
depending on the device (iPhone 4 vs iMac 2016)
...
How do I figure it out?
Your bullet list is a good start. Memory would be another consideration. A static variable will stay in memory from the time it is actually initialized until the termination of the app. Obviously a local variable will be deallocated at the end of the method (assuming no further references).
Readability is something to consider too. The reallocation line is much easier to read than the dispatch_once setup.
For a little array, I'd reallocate as the first choice. The overhead is tiny. Unless you are creating the array in a tight loop, performance will be negligible.
I would use dispatch_once and a static variable for things that take more overhead such as creating a date formatter. But then there is the overhead of reacting to the user changing the device's locale.
In the end, my thought process is to first use reallocation. Then I consider whether there is tangible benefit to using static and dispatch_once. If there isn't a worthwhile reason to use a static, I leave it a local variable.
Use static if the overhead (speed) of reallocation is too much (but not if the permanent memory hit is too large).
Your second approach is more complex. So you should use it, if it is needed, but not as a default.
Typically this is done when the object creating is extreme expensive (almost never) or if you need a single identity of the instance object (shared instance, sometimes called singleton, what is incorrect.) In such a case you will recognize that you need it.
Although this question could probably be closed as "primarily opinion-based", I think this question addresses a choice that programmers frequently make.
The obvious answer is: don't optimize, and if you do, profile first - because most of the time you'll intuitively address the wrong part of your code.
That being said, here's how I address this.
If the needed object is expensive to build (like the formatters per documentation) and lightweight on resources, reuse / cache the object.
If the object is cheap to build, create a new instance when needed.
For crucial things that run on the main thread (UI stuff) I tend to draw the line more strict and cache earlier.
Depending on what you need those objects for, sometimes there are valid alternatives that are cheaper but offer a similar programming comfort. For example, if you wanted to look up some chessboard coordinates, you could either build a dictionary {#"a1" : 0, #"b1" : 1, ...}, use an array alone and the indices, take a plain C array (which now has a much less price tag attached to it), or do a small integer-based calculation.
Another point to consider is where to put the cached object. For example, you could store it statically in the method as in your example. Or you could make it an instance variable. Or a class property / static variable. Sometimes caching is only the half way to the goal - if you consider a table view with cells including a date formatter, you can think about reusing the very same formatter for all your cells. Sometimes you can refactor that reused object into a helper object (be it a singleton or not), and address some issues there.
So there is really no golden bullet here, and each situation needs an individual approach. Just don't fall into the trap of premature optimization and trade clear code for bug-inviting, hardly readable stuff that might not matter to your performance but comes with sure drawbacks like increased memory footprint.
dispatch_once_t
This allows two major benefits: 1) a method is guaranteed to be called only once, during the lifetime of an application run, and 2) it can be used to implement lazy initialization, as reported in the Man Page below.
From the OS X Man Page for dispatch_once():
The dispatch_once() function provides a simple and efficient mechanism to run an initializer exactly once, similar to pthread_once(3). Well designed code hides the use of lazy initialization.
Some use cases for dispatch_once_t
Singleton
Initialization of a file system resource, such as a file handle
Any static variable that would be shared by a group of instances, and takes up a lot of memory
static, without dispatch_once_t
A statically declared variable that is not wrapped in a dispatch_once block still has the benefit of being shared by many instances. For example, if you have a static variable called defaultColor, all instances of the object see the same value. It is therefore class-specific, instead of instance-specific.
However, any time you need a guarantee that a block will be called only once, you will need to use dispatch_once_t.
Immutability
You also mentioned immutability. Immutability is independent of the concern of running something once and only once--so there are cases for both static immutable variables and instance immutable variables. For instance, there may be times when you need to have an immutable object initialized, but it still may be different for each instance (in cases where it's value depends on other instance variables). In that case, an immutable object is not static, and still may be initialized with different values from multiple instances. In this case, a property is derived from other instance variables, and therefore should not be allowed to be changed externally.
A note on immutability vs mutability, from Concepts in Objective-C Programming:
Consider a scenario where all objects are capable of being mutated. In your application you invoke a method and are handed back a reference to an object representing a string. You use this string in your user interface to identify a particular piece of data. Now another subsystem in your application gets its own reference to that same string and decides to mutate it. Suddenly your label has changed out from under you. Things can become even more dire if, for instance, you get a reference to an array that you use to populate a table view. The user selects a row corresponding to an object in the array that has been removed by some code elsewhere in the program, and problems ensue. Immutability is a guarantee that an object won’t unexpectedly change in value while you’re using it.
Objects that are good candidates for immutability are ones that encapsulate collections of discrete values or contain values that are stored in buffers (which are themselves kinds of collections, either of characters or bytes). But not all such value objects necessarily benefit from having mutable versions. Objects that contain a single simple value, such as instances of NSNumber or NSDate, are not good candidates for mutability. When the represented value changes in these cases, it makes more sense to replace the old instance with a new instance.
A note on performance, from the same reference:
Performance is also a reason for immutable versions of objects representing things such as strings and dictionaries. Mutable objects for basic entities such as strings and dictionaries bring some overhead with them. Because they must dynamically manage a changeable backing store—allocating and deallocating chunks of memory as needed—mutable objects can be less efficient than their immutable counterparts.
I'm designing a object persistent code.
IMO, memory snapshot is fastest, reliable and compact persistent method within a few limitation.
It's easy with C structs. I can layout all objects' memory layout manually. I can save all references as index of object collection. So reference is not a problem.
Anyway I want to try this with Objective-C objects. To do this, objects must be positioned in specific location of memory. So, if I can specify memory location of allocation, I can snapshot the memory. And when restoring, I can get an object at specific address.
Of course, all of these are machine-specific and needs many tricks, but it's fine to me.
The only problem is I don't know way to specify location of new Objective-C object. How can I do this?
Generally people use NSCoding and NSKeyedArchiver (or some custom subclass thereof). I think your C method would have worked before the 64-bit runtime, since the data part of objects was implemented using structs, but I think the new runtime's use of nonfragile instance variables would complicate matters. In any event, the program that loads the persistent objects still has to have the class definitions for them, either hard-coded or loaded via bundles.
I'm creating a library that will be used by multiple types of iOS apps. Part of my API allows a user to specify routines that will be used for the library's allocations. My library is implemented mostly in C++, so this has been straightforward so far.
However, I've recently been adding some user interface functionality to the library: displaying a UIWebView using a custom view controller. I'm not sure how to ensure that my allocators are used for these objects.
How can I ensure that all of the Cocoa UI objects created by my library are allocated with my own functions?
I've tried a few things including overriding -initWithZone and calling CFAllocatorSetDefault before my -init. None of them have worked yet; and honestly I'm still a beginner with Objective C and Cocoa, so I'd like to know what the "correct" way to do this is.
I'm unable to find evidence of it now, but it certainly was the case that CFAllocator, malloc_zone_t and NSZone were all toll-free bridged. So you could just cast your allocator to an NSZone and pass it along.
I think the problem you're going to face is that NSZone was added at NextStep so as to allow a program to maintain multiple heaps, with the feeling being that it would allow programmers to keep related objects close to one another in memory — which is good for caching — and in some cases to throw away entire object graphs without walking the graph, which is obviously fast. However the former was of little benefit in practice and the latter is more likely to create problems than to be of actual benefit. So Apple has back-peddled from NSZones, gradually turning the related runtime calls into no-ops and removing detailed documentation. Apple's feeling is that, at the Objective-C level, you should not only maintain only a single heap (which is a side issue from your point of view) but that they'll always know best how to maintain it.
EDIT: an alternative idea is to replace NSObject's alloc, that being the thing that creates memory. The Objective-C runtime is well-defined enough that we know exactly what behaviour alloc exhibits, so that a vanilla version might be:
+ (id)alloc
{
Class *newInstance;
// we'll use calloc to ensure we get correct initial behaviour of
// everything equal to 0, and use the runtime's class_getInstanceSize
// so that we're allocating the correct amount of memory irrespective
// of whether this call has fallen through from a subclass
newInstance = (Class *)calloc(1, class_getInstanceSize(self));
// the thing that defines a class is that the first thing stored in
// it is the isa pointer, which points to the metaclass. So we'll
// set the isa pointer appropriately
*newInstance = self;
return (id)newInstance;
}
To replace NSObject's normal init, you'd probably want to define your alternative as a category method on NSObject named, say, customInit, then use class_getClassMethod, class_getMethodImplementation and method_setImplementation directly on [NSObject class] to switch it into place. See the Object-C Runtime Reference for documentation on those.
In a project with garbage collection set to required: If I instantiate an object in Interface Builder and add it to the XIB/NIB, do I need to assign this object to some outlet to avoid it being garbage-collected, or is that taken care through some other means?
Top level objects need to be assigned to an outlet somewhere or attached to some variable using the top level objects array when instantiating the nib. Otherwise, they are useless to you anyway. A view which is contained within another view or window is in that views instance variables so it is safe.
I just built a small test project. With GC, the object created through Interface Builder gets collected soon afterwards. So the answer to the question is: yes.
I did a bit more testing:
With classical reference counting this does not happen. This is possibly what one would expect, but it is also probably a memory leak. Not sure here. (If not, and the NIB/XIB-contained objects get released when the file's owner is release, e.g., then this would constitute a significant difference in behavior between GC and classical RC.)
With ARC enabled, I did not find a way to tell. There is probably some function I could put a breakpoint on and wait for the specific object fly by.
Edit:
I reviewed the documentation, and it states it quite clearly. Missed that the first time around:
You typically need strong references to top-level objects to ensure that they are not deallocated; you don’t need strong references to objects lower down in the graph because they’re owned by their parents, and you should minimize the risk of creating strong reference cycles.
From: Resource Programming Guide, Managing the Lifetimes of Objects from Nib Files
As is common knowledge, calls to alloc/copy/retain in Objective-C imply ownership and need to be balanced by a call to autorelease/release. How do you succinctly describe where this should happen? The word "succinct" is key. I can usually use intuition to guide me, but would like an explicit principle in case intuition fails and that can be use in discussions.
Properties simplify the matter (the rule is auto-/release happens in -dealloc and setters), but sometimes properties aren't a viable option (e.g. not everyone uses ObjC 2.0).
Sometimes the release should be in the same block. Other times the alloc/copy/retain happens in one method, which has a corresponding method where the release should occur (e.g. -init and -dealloc). It's this pairing of methods (where a method may be paired with itself) that seems to be key, but how can that be put into words? Also, what cases does the method-pairing notion miss? It doesn't seem to cover where you release properties, as setters are self-paired and -dealloc releases objects that aren't alloc/copy/retained in -init.
It feels like the object model is involved with my difficulty. There doesn't seem to be an element of the model that I can attach retain/release pairing to. Methods transform objects from valid state to valid state and send messages to other objects. The only natural pairings I see are object creation/destruction and method enter/exit.
Background:
This question was inspired by: "NSMutableDictionary does not get added into NSMutableArray". The asker of that question was releasing objects, but in such a way that might cause memory leaks. The alloc/copy/retain calls were generally balanced by releases, but in such a way that could cause memory leaks. The class was a delegate; some members were created in a delegate method (-parser:didStartElement:...) and released in -dealloc rather than in the corresponding (-parser:didEndElement:...) method. In this instance, properties seemed a good solution, but the question still remained of how to handle releasing when properties weren't involved.
Properties simplify the matter (the rule is auto-/release happens in -dealloc and setters), but sometimes properties aren't a viable option (e.g. not everyone uses ObjC 2.0).
This is a misunderstanding of the history of properties. While properties are new, accessors have always been a key part of ObjC. Properties just made it easier to write accessors. If you always use accessors, and you should, than most of these questions go away.
Before we had properties, we used Xcode's built-in accessor-writer (in the Script>Code menu), or with useful tools like Accessorizer to simplify the job (Accessorizer still simplifies property code). Or we just typed a lot of getters and setters by hand.
The question isn't where it should happen, it's when.
Release or autorelease an object if you have created it with +alloc, +new or -copy, or if you have sent it a -retain message.
Send -release when you don't care if the object continues to exist. Send -autorelease if you want to return it from the method you're in, but you don't care what happens to it after that.
I wouldn't say that dealloc is where you would call autorelease. And unless your object, whatever it may be, is linked to the life of a class, it doesn't necessarily need to be kept around for a retain in dealloc.
Here are my rules of thumb. You may do things in other ways.
I use release if the life of the
object I am using is limited to the
routine I am in now. Thus the object
gets created and released in that
routine. This is also the preferred
way if I am creating a lot of objects
in a routine, such as in a loop, and
I might want to release each object
before the next one is created in the
loop.
If the object I created in a method
needs to be passed back to the
caller, but I assume that the use of
the object will be transient and
limited to this run of the runloop, I
use autorelease. Here, I am trying to mimic many of Apple's convenience routines. (Want a quick string to use for a short period? Here you go, don't worry about owning it and it will get disposed appropriately.)
If I believe the object is to be kept
on a semi-permanent basis (like
longer than this run of the runloop),
I use create/new/copy in my method
name so the caller knows that they
are the owner of the object and will
have to release the object.
Any objects that are created by a
class and kept as a property with
retain (whether through the property
declaration or not), I release those
in dealloc (or in viewDidUnload as
appropriate).
Try not to let all this memory management overwhelm you. It is a lot easier than it sounds, and looking at a bunch of Apple's samples, and writing your own (and suffering bugs) will make you understand it better.