A note on Objective-C singletons
I'm not a big fan of singletons, especially when they are used as they often are - as glorified globals. That being said, it occasionally makes sense to have some kind of shared instance of an object; not a true singleton that strictly prevents more than one allocation, but a convenient default instance.
Apple uses this pattern frequently throughout their frameworks: [NSUserDefaults standardUserDefaults]
, [UIScreen mainScreen]
and many, many more.
Conceptually, I like to think of these methods as convenient accessors to instances representing a shared or common resource rather than singletons and I still try and avoid using them as globals where possible.
Singletons: the wrong way
If you were trying to find out a way of implementing a singleton or shared instance in Objective-C, you might well find yourself implementing Apple's own example. You might even find yourself using Matt Gallagher's SynthesizeSingleton
macro.
No disrespect to Matt, but please don't do this. You almost certainly don't need such a strict implementation. Furthermore, much of the code isn't even relevant in our shiny ARC future.
Singletons: the right way
Up until recently, if anybody asked me what the best way of going about creating a singleton in Objective-C is, I'd point them towards Chris Hanson's great article on the subject. In fact, I still recommend you read it.
But there is an even easier way using Grand Central Dispatch; I've seen this mentioned in several Apple WWDC videos and Colin Wheeler mentions it in this blog post but it doesn't seem to have gained much traction, possibly due to people still supporting iOS 3. But with iOS 5 round the corner, I think it's time to move on and embrace blocks, GCD and eventually, ARC.
Here's what the GCD (and ARC) version looks like:
The block given to dispatch_once
will, as the name implies, only ever be called once. This will ensure only one instance is created. It's also fast and thread safe: no synchronized
or nil checks required.
We can go one step further and wrap this up in a convenient macro. Now all you need to do is this:
A bit simpler than the Apple version, don't you think?