If you’re a working programmer, you’ve likely used or at least heard of design patterns. A design pattern is a solution to a design problem. It can be a small problem such as figuring out how two objects might collaborate effectively, or a larger problem such as how we should isolate layers in an enterprise application.
If you work with Cocoa, you’re working with some design patterns already, though these are so ingrained in the API you may not think of them as such. The most common one is the Delegate pattern. We use delegates all over the Cocoa API to get around having to extend built in classes, most of which have to do with creating UI elements. Instead of overriding UITextField in an iPhone application, we can assign the field a delegate object, allowing us to write only the minimal amount of custom behavior we need in some other class. When there’s a customization point in the program, an object will notify the delegate allowing us to take action or to send advice back to the calling object.
One very common pattern that doesn’t get discussed a lot in Cocoa circles, but I think is very useful, is the Singleton pattern. A singleton is a class for which there exists only a single instantiated object. This object is generally used to model a shared resource. The Cocoa API uses the singleton pattern though it may not be obvious if you’re not used to making your own singletons. The NSApplication and UIApplication classes implement the singleton pattern. If you want to interact with the application object, you need to get an instance to the single object that models the application:
// Some singletons in the CocoaTouch libraries
UIApplication *applicationSingleton = [UIApplication sharedApplication];
UIAccelerometer *accelerometerSingleton = [UIAccelerometer sharedAccelerometer];
In an iPhone application, there’s conceptually only one UIApplication instance – the application that’s currently executing. There’s only one UIAccelerometer instance – the one that governs access to the accelerometer on the device. In idiomatic Cocoa programming, we never instantiate a singleton object, we ask the class for a reference to the singleton, and the method name that gives it to us usually starts with the word “shared” to imply that it is a singleton instance.
In some modern languages, support for the Singleton pattern is baked into the standard libraries or even into the language itself. Take for example this Ruby singleton:
require 'singleton'
class RadioTuner
include Singleton
def set_station(station)
@current_station = station
end
def current_station
@current_station
end
end
tuner = RadioTuner.instance
tuner.set_station(99.9)
puts tuner.current_station
The singleton module is available in the ruby standard library.
The Scala language takes this one step further by supporting singletons directly in the language:
object RadioTuner { private var _currentStation: Float = 0.0f; def setStation(s: Float) = synchronized { _currentStation = s } def currentStation: Float = synchronized { _currentStation; } } RadioTuner.setStation(99.9f); println(RadioTuner.currentStation);
In Scala, we use the keyword “object” to declare a singleton object. Scala goes as far as banning static members of classes from language. In the interest of object oriented purity, you need to use the singleton pattern.
While many of us may be new to Objective-C, it is not a new language. Unlike relative newcomers like Ruby and Scala, Objective-C doesn’t bake the singleton pattern into the language. In Objective-C we have to take care of the details of implementing the singleton ourselves. We need to create and manage the only instance of our singleton class, and we need to guarantee that there can be only one instance of the class in a running program.
Let’s assume that we had some hardware tuner in our computer that we wanted to expose as a shared singleton object. Let’s start by making a new Command Line Tool in Xcode:
Name the project “Singleton” or whatever makes you happy.
Let’s dive right in and define our singleton. Add a new Objective-C class to the project and name it “RadioTuner”. This will represent our imaginary radio tuner. If we look at our Scala and Ruby implementations, we see that we need to be able to do three things with our singleton:
With that in mind, let’s create the header:
#import
/**
This class simulates access to a hardware radio tuner. In our example
we assume that our computer has a single radio tuner that must be shared.
*/
@interface RadioTuner : NSObject {
NSDecimalNumber *currentStation;
}
/**
Returns an instance to the shared singleton which governs access to the
hardware radio tuner.
@returns The shared tuner object
*/
+ (RadioTuner *)sharedTuner;
/**
Sets the tuner to the desired station
@param station the new station frequency
*/
- (void)setStation:(NSDecimalNumber *)station;
/**
Get the current station
@returns returns the current statiion to which the tuner is tuned.
*/
- (NSDecimalNumber *)currentStation;
@end
Following Cocoa naming conventions, we’re declaring a class method named +sharedTuner. This will allow us to get a reference to the singleton object. The -setStation: and -currentStation methods will be called on the singleton itself to allow use to change and access the state of the tuner.
To store the currentStation, we’ll use an instance of NSDecimalNumber.
This is all we need for the header. For the real meat of things, we need to look at how we implement this. Most of the work is will be in the +sharedTuner method and methods that support the singleton behavior. We need to guarantee that when code calls [RadioTuner sharedTuner] we always return the same object, and that this is the only way possible to get a reference to a RadioTuner object.
To start off, we need a way to store the shared instance. Remember that since this is a singleton, we need to have a instance of the object to hand out. In many languages we’d use a class attribute. Objective-C doesn’t have this concept, so we have to make our own fun.
In RadioTuner.m, add the following line to create a static variable to hold our shared tuner instance:
#import "RadioTuner.h"
static RadioTuner *sharedInstance = nil;
@implementation RadioTuner
...
There’s nothing magic here; this is your basic C language static variable declaration. A static variable lives for the scope of the entire program.
Now we write the +sharedTuner method:
+ (RadioTuner *)sharedTuner
{
@synchronized (self) {
if (sharedInstance == nil) {
[[self alloc] init];
}
}
return sharedInstance;
}
There are a few things to notice here. First, this method is synchronized. The reason for this is pure paranoia. We don’t want to find ourselves in a situation where more than one thread is calling this method at the same time. It’s possible, however remote, that we could end up with more than one instance of our singleton which is bad. This is significantly more paranoid than Apple’s advice on creating singletons and The Big Nerd Ranch’s method (see iPhone Programming, 1st ed. page 186). My assumption is that in most cases you can get away without the synchronization, but I’m going to play paranoid in this example.
The second odd thing about this method is we never assign a value to the sharedInstance variable! This seems counter intuitive, but there is a good reason for this. To illustrate why things work this way, let’s take a look at the next method we need to implement, +allocWithZone:
+ (id)allocWithZone:(NSZone *)zone
{
@synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [super allocWithZone:zone];
return sharedInstance;
}
}
return nil;
}
First off, we’re not overriding +alloc, we’re overriding +allocWithZone:. This is because +alloc will call +allocWithZone: behind the scenes. When we allocate the object, we’re requesting memory from the system for our object. When we call +allocWithZone:, we’re asking for memory with a specific zone. With out getting into too much detail, a zone is a range of virtual memory. The idea behind using zones is to allow us to group related objects in the same virtual memory page in an attempt to reduce page thrashing. For the more curious, you can check out Apple’s documentation on memory zones.
What we care about here is that our implementation of +allocWithZone: only allocates memory if sharedInstance is nil. If sharedInstance has already been set, we return nil. What this means is that only the first call to [RadioTuner alloc] will allocate memory. All subsequent calls will return nil. This guarantees that if some piece of code attempts to manually allocate an instance, it will likely fail. In the case that the code is the first call to +alloc, it will get a reference to the sharedInstance.
Basically, this implementation guarantees that you can only ever instantiate one copy of RadioTuner. Because we need to be defensive about allocation, this is where the assignment of the sharedInstance variable needs to occur.
This is a good start, but we’re not out of the woods yet. We need to override -copyWithZone: in case we ever try to make a copy of our singleton instance:
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
Notice that our implementation doesn’t make a copy at all; it returns itself. We do this because the singleton pattern dictates that there can only ever be one instance. So you can try to copy the object, but you’re only ever going to get a reference to the same object.
We’re almost done with the boilerplate code that will support the singleton pattern. There is one more problem to consider. Assuming we’re working with reference counting, we need to make sure that the Objective-C runtime never deallocates our object. After all, a singleton models some shared resource that lives for the scope of our application. Imagine if you were able to deallocate the shared NSApplication instance – it doesn’t make sense.
Let’s override some methods to protect our object from deallocation:
- (id)retain
{
return self;
}
- (void)release
{
// do nothing
}
- (id)autorelease
{
return self;
}
- (NSUInteger)retainCount
{
return NSUIntegerMax; // This is sooo not zero
}
If you’re not familiar with retain counts, you should check out Apple’s documentation on basic memory management, or you can take a look at my previous post on memory management.
Our implementation of -retain doesn’t alter the retain count of the object. Also, -release doesn’t decrement the retain count, so it’s not possible to reduce it to zero (which would cause deallocation). Our implementation of -autorelease maintains the external behavior, but it does not add our object to an autorelease pool. Finally we have our implementation of -retainCount which returns the biggest integer we can model on the hardware. On my machine, this returns 4,294,967,295. That’s really really not zero. This protects our singleton from ever being deallocated.
I suspect in practice that this is overkill. Apple’s documentation suggests we override all of these methods, though Conway and Hillegas advise us to only override -release. My advice is to be paranoid. It doesn’t hurt to override these methods.
Now that we’ve guaranteed that we can only create a single instance of our class that can never be deallocated, we can implement the actual logic of our make believe radio tuner:
- (id)init
{
@synchronized(self) {
[super init];
currentStation = [[NSDecimalNumber alloc] initWithString:@"0.0"];
return self;
}
}
- (void)setStation:(NSDecimalNumber *)station
{
@synchronized(self) {
if (currentStation != station) {
[currentStation release];
currentStation = [station retain];
}
}
}
- (NSDecimalNumber *)currentStation
{
@synchronized(self) {
return currentStation;
}
}
First off we have a basic -init method. This sets up a default value. -setStation: and -currentStation are fairly straight forward. Technically we could have skipped implementing -setStation: and -currentStation and synthesized them as Objective-C 2.0 properties, but I’ve included implementations so you could see the details. Notice that all of these methods are synchronized. I recommend synchronizing any method in your singletons that accesses or alters shared state unless you don’t have thread safety as a goal.
One last thing to note is that there is no -dealloc method. Since we’ve gone through all the trouble of making sure -dealloc will never be called, we don’t get anything from implementing the method. Our singleton object will be evicted from memory when the program terminates. This presents something of a problem for cleanup. In general, you can never count on using -dealloc for cleanup as it might not ever be called, not just for our singleton. When a program terminates, there is no guarantee that every remaining object will get a -dealloc message; it’s much more efficient for the operating system to evict them from memory and go on its way. So, if your singleton needs to be cleaned up, you should create a method to do that cleanup operation and make sure you invoke it when your application quits. For example, if you were writing an Mac OS X application, you could implement the -applicationShouldTerminate: method in your NSApplication delegate and call the cleanup method.
To make use of our new singleton, add the following code to Singleton.m:
#import "RadioTuner.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
RadioTuner *tuner = [RadioTuner sharedTuner];
NSDecimalNumber *station = [NSDecimalNumber decimalNumberWithString:@"99.9"];
[tuner setStation:station];
NSLog(@"%@", [tuner currentStation]);
[pool drain];
return 0;
}
Run the code, and you’ll see our current station printed to the console. Perhaps this isn’t the most exciting singleton, but you can build any singleton you need using this technique.
Click here to download the completed project.
We can further differentiate singletons as either eager or lazy. An eager singleton is one that is instantiated before your first use of it. A lazy singleton is not instantiated until your first request to use it. We’ve implemented a lazy singleton. Our singleton instance will not exist until the first call to [RadioTuner sharedTuner].
If for some reason it took a long time to create our singleton instance, we might prefer an eager singleton. People are more forgiving of an application taking a while to load than applications slowing down during use for no apparent reason.
You might think this is a viable way to implement an eager singleton in Objective-C:
#import "RadioTuner.h"
static RadioTuner *sharedInstance = [RadioTuner sharedTuner];
@implementation RadioTuner
Unfortunately we can’t set the initial value of sharedInstance in RadioTuner.m. The compiler will complain that you’re trying to initialize the variable with a non-constant value. Much like we would have to hook into the application lifecycle to cleanup our singleton, we’d also have to eagerly create singleton instances in a similar fashion. The easiest route is to call [RadioTuner sharedTuner] in your application delegate’s -applicationDidFinishLaunching: method or something similar.
You want to create a singleton when you are certain that there should only ever be one instance of a particular class and it needs to be accessible by a well-known access point. NSApplication is a great example of this. You can access the shared application from anywhere in a Cocoa program using [NSApplication sharedApplication]. Furthermore, you’d only ever want to model the running application once, and you want access to that model for the entire life of the application. If what you’re attempting to model fits this pattern, then a singleton is a good way to go.
In many respects our application delegate objects acts as a sort of de-facto singleton. Generally we only have one instance of our application delegate class, it lives for the duration of the application, and it’s accessible via [[NSApplication] delegate]. In fact, we tend to put a lot of shared resources into the application delegate simply because it is so easily accessible and there is generally only one instance. The delegate of course is not a true singleton. In fact, it’s quite possible to alter the application’s delegate while the application is executing, though I don’t think that’s common in practice. In my experience, when you find that you’re embedding a lot of shared resources into your application delegate simply because it’s a convenient place to access them, that’s a good place to start thinking about singletons.
While creating singletons in Objective-C might be more involved than in more modern languages, it’s not very difficult. We do need to create some boilerplate code to support the proper behavior, but once you know what’s required and understand what it’s doing, you can get down to the work of implementing the logic of your singletons, and the result is better organized code.