Next article: Friday Q&A 2009-10-09: Defensive Programming
Previous article: Friday Q&A 2009-09-25: GCD Practicum
Tags: cocoa fridayqna objectivec singleton
It's time for another Friday Q&A. I hope everyone who had a chance to go to C4 had a good time and is back home safe and sound. This week I'm going to discuss singletons, both how to make them and when to use them, as suggested by Jon Trainer.
What Is It?
Most of you probably know this already, but for the sake of completeness, a singleton is an object which is restricted to be the only instance of its class. In other words, within any given process, you have the concept of the Foo
, rather than a Foo
.
Benefits
Why would you use a singleton instead of a regular class? There are a few basic reasons:
- Global access: A singleton is essentially shared throughout the entire program, making it easier to coordinate activities. A major example of this in Cocoa is
NSNotificationCenter
. - Resource management: Having a single instance of a class is appropriate if that class represents an entity which is inherently singular. An example of this in Cocoa is
NSApplication
. - Grouping functionality: Sometimes you have a lot of similar functionality that logically goes together but which doesn't necessarily fit into the object model because there's no long-term state. By using a singleton you simplify access to this functionality.
NSWorkspace
is an exmple of this usage of a singleton in Cocoa. - Lazy initialization: Properly-written singleton classes aren't instantiated until something asks for them, meaning that the resources occupied by the singleton aren't allocated until they're needed.
Singletons aren't always appropriate. (In fact, they're almost always not appropriate. Just look at the proprotion of singletons to normal classes in any given program.) In general you should not use one unless you need it, but there are some specific pitfalls to look out for:
- Shared global state: Singletons are inherently globally accessible, which means that any state which exists as part of the singleton can be accessed and potentially changed from any part of the program. Good encapsulation of singleton state can help with this a lot, but if you're not careful then the problem can be much like that of global variables. This can be particularly vicious in a multithreaded environment. Many Cocoa singletons suffer from not being thread safe and their global accessibility makes them inherently limited to only being used from the main thread.
- Over-specialized code: You thought there would only be one, so you made a singleton around it. Now there are two. All of your code assumes that there is only one. Time for a big, painful rewrite.
How to Make One
At its most basic, a singleton is implemented like this:
+ (id)sharedFoo
{
static Foo *foo = nil;
if(!foo)
foo = [[self alloc] init];
return foo;
}
Right about now, a bunch of people are thinking back to a certain Apple document on singletons which shows a much more complicated implementation. There are basically two advantages to Apple's version which this doesn't have.
- Thread safety: Apple's version correctly deals with the case where multiple threads try to access the singleton before it's been created.
- Programmer safety: Apple's version tries to cover for a lot of dumb mistakes a programmer might make, like incorrectly releasing a singleton.
release
to do nothing, override dealloc
to log an error and abort the program.
Furthermore, it's not always necessary to really strictly enforce singleton-ness. NSFileManager
is a good example of this from Cocoa. Through 10.4 it was a singleton, and not thread safe and thus could only be used on the main thread. Starting in 10.5, Apple allowed the creation of separate instances which could then be safely used on other threads. Your code might well want to do the same thing. Often, providing the shared globally-accessible instance is the major benefit of having a singleton, and there's no need to prohibit other instances being created on the side.
This brings up one tip I want to mention regarding singletons: always implement a dealloc
method and keep it up to date. With a singleton, it's tempting to forget about releasing resources because it will live for the life of the program. But it's much easier to write code to release resources as you write the rest of the code than it is to add it in later, and you'll be glad you did if you ever decide to make your singleton no longer be single.
Thread Safe Singletons
What about when thread safety is necessary?
One really simple way to deal with this is to simply toss in a lock, like so:
+ (id)sharedFoo
{
static Foo *foo = nil;
@synchronized([Foo class])
{
if(!foo)
foo = [[self alloc] init];
}
return foo;
}
Note: this makes it safe to retrieve the shared singleton from multiple threads, but does not automatically make it safe to use it. Making the singleton's code be thread safe is up to you!
This code is kind of slow, though. Taking a lock is somewhat expensive. Making it more painful is the fact that the vast majority of the time, the lock is pointless. The lock is only needed when foo
is nil
, which basically only happens once. After the singleton is initialized, the need for the lock is gone, but the lock itself remains.
One fix for this is to take advantage of the Objective-C runtime and use the +initialize
method instead:
static Foo *gSharedFoo;
+ (void)initialize
{
if(self == [Foo class])
gSharedFoo = [[self alloc] init];
}
+ (id)sharedFoo
{
return gSharedFoo;
}
+initialize
always runs before +sharedFoo
can execute. The only downside to this approach is that +initialize
will run if any message is sent to your class, possibly initializing the singleton earlier than necessary.
Double-Checked Locking
If you search on the above phrase you'll find a bunch of web pages talking about how this technique is a bad idea. And it is, for platform-independent code. However, if you can assume some knowledge of your target platform (and hey, we're all doing OS X development here) then it can be done safely.
The basic concept of double-checked locking is to have two copies of the if statement that checks to see if the singleton has been initialized. An outer if statement checks to see if the singleton is initialized. If it is, then return it, no lock taken. If it's not, then take the lock and check the singleton again. This ensures that all threads which might try to initialize the singleton are synchronized via the lock.
The problem with this approach is out-of-order memory access, either generated by the compiler or performed by the CPU. For more information on this, you can read my article on using the volatile
keyword in a multithreaded context.
The solution to the CPU side is to insert a memory barrier when writing and when reading. Memory barriers enforce in-order access to memory locations by the CPU. In OS X, a memory barrier function is available in the libkern/OSAtomic.h
header, called OSMemoryBarrier
. The solution to the compiler side is to use volatile
on the shared variable.
Thus our double-checked locking singleton method looks like this:
+ (id)sharedFoo
{
static Foo * volatile foo = nil;
if(!foo)
{
@synchronized([Foo class])
{
if(!foo)
{
Foo *tmpFoo = [[self alloc] init];
OSMemoryBarrier();
foo = tmpFoo;
}
}
}
OSMemoryBarrier();
return foo;
}
Grand Central Dispatch
If you can target 10.6+, Grand Central Dispatch provides an extremely fast one-time initialization API which is perfect for a singleton. Not only is it fast, but it's also extremely easy to use. It's a win all around!
Here's what the GCD solution looks like:
+ (id)sharedFoo
{
static dispatch_once_t pred;
static Foo *foo = nil;
dispatch_once(&pred, ^{ foo = [[self alloc] init]; });
return foo;
}
dispatch_once
function takes care of all the necessary locking and synchronization. It's actually a macro which expands to something much like the double-checked locking solution above. However, using some extremely underhanded trickery, it doesn't even need to take the hit of a memory barrier. In the common case, this code is a single if check followed by a return. Aside from the fact that it's examining two variables instead of one (an extremely small cost) it's as fast as the non-thread-safe version I started out with, and very nearly as simple. Nice!
Advanced Topics
There are a couple of interesting advanced techniques with singletons that I want to cover briefly. I won't go over how to build them, but think of them as exercises for the reader.
One such thing is an automatic singleton class. This would be a class which you subclass and which automatically provides all the necessary infrastructure to provide a singleton of that class. The superclass would have a method which returns (and creates, if necessary) the singleton instance of the subclass on which it was invoked. Managing the singletons would probably involve a global dictionary mapping classes to their singleton instances.
Another interesting variant, which I've never actually seen implemented, is a destroyable singleton. Rather than create a single shared instance which lives forever, the singleton accessor would not take ownership of the singleton object, and would allow it to be destroyed when all other code gives up ownership of it. In Cocoa, this would be accomplished by returning an autoreleased singleton, or when programming with garbage collection, by using a __weak
global to store it. Making this thread safe would be a challenge, to ensure that duplicates aren't created but that old ones aren't ressurected as they're being destroyed.
Conclusion
That wraps up this week's edition. Now you know all about singletons, probably far more than you wanted to know.
Come back next week for another one. As always, Friday Q&A is driven by your submissions. The better the submissions I get, the better the articles you get to read! Send in your ideas for future articles today!
Comments:
Curiously, assuming that an automatic singleton superclass is feasible and safe for production code, have you ever written or seen one? It seems to me like the perfect addition to my general-purpose Cocoa framework. (Granted, it's likely to almost always be the wrong answer, but the implementation of it is just tricky enough that it's annoying to rewrite over and over.)
I also wanted to point out that this code is generally not reentrant for the -init method. If the -init method calls the shared (or global) accessor, it will loop forever. The fix for this that I use is to assign the global variable as foo = [self alloc] first, then reassign and initialize it via foo = [foo init].
Steven Degutis: I think I've seen such things around (cocoadev.com maybe) but don't recall. As for reentrancy in the shared getter, reassigning is a bad idea, due to the fact that init can return a different object. Better would be to simply refer to self in your initializer, since that's what you're really after anyway.
Overall I don't think it makes a big difference, but real instances are somewhat cleaner and not much harder.
Jeff:
Not that I was asked, but I'd say the difference between singletons and a class with only class methods, are the instance variables. You would have to create a lot of static vars in your class, to act as ivars, and that just feels weird... not to mention, those pseudo-ivars aren't going to work well with things like KVC/KVO and @properties, and won't be accessible from within subclasses either, among other things.
I'd love to hear about uniquing objects—that is, ensuring that only a single object of a given class with (say) a given ID number is allocated in the application at a time. I've done this a few times, but I've never worked out how to allow them to be deallocated when they're no longer used—and there may be other tricks I don't know about.
+ (id)sharedFoo {
static Foo* volatile foo = nil;
if (!foo) {
Foo* tmpFoo = [[self alloc] init];
bool set = OSAtomicCompareAndSwapPtrBarrier(nil, tmpFoo, (void*volatile*)&foo);
if (!set) [tmpFoo release];
}
return foo;
}
It would do a bit of wasted work if the first few calls do happen simultaneously, but is this a good solution for pre-GCD code?
If you're using garbage collection, then life is easy. Use an NSMapTable with weak objects. Wrap it in a lock if you need it to be thread safe.
Non-GC non-thread-safe is also fairly easy. Same NSMapTable setup, then have each cached object clear its own entry in -dealloc.
Non-GC thread-safe is a bit harder. You have to watch out for the case where one thread releases the last reference to a cached object, and then another thread tries to retrieve that reference before the object is actually removed from the NSMapTable. To avoid this, you'll probably want to implement your own reference counting mechanism (override retain/release) so that these are protected by the same lock that protects the NSMapTable.
natevw: I think that you also need an OSMemoryBarrier() before the return foo; for this to be 100% correct. (I think we discussed this before and I thought this was ok, but now I'm less certain.) And of course your singleton object needs to be able to tolerate multiple (unused) instances for a short period.
ChristopherAtlan: Yes, that will work fine as well, although it's a bit slower. I also don't like the fact that they don't support a context pointer to the function the way dispatch_once does. However, it's perfectly fine for this usage.
static Foo *gSharedFoo;
I think it's a better to use the new associated object feature:
+(void)initialize{
static dispatch_once_t pred;
Foo *foo;
dispatch_once(&pred, ^{
foo = [[[self alloc] init] release];
objc_setAssociatedObject(NSApp, @selector(sharedFoo), OBJC_ASSOCIATION_RETAIN);
});
return foo;
}
+(id)sharedFoo{
return objc_getAssociatedObject(NSApp, _cmd);
}
@implementation SingletonHelper
+ (id)initializeSingletonClass:(Class)kls onceT:(dispatch_once_t)pred;
{
// Add the [kls sharedKls] message
NSString *msg_name = [NSString stringWithFormat:@"shared%@", NSStringFromClass(kls)];
SEL sel = NSSelectorFromString(msg_name);
Method m = class_getClassMethod(SingletonHelper, @selector(getSharedInstance));
class_addMethod(kls, sel, method_getImplementation(m), "@@:");
// initialize the shared instance, and return
id ret;
dispatch_once(&pred, ^{
ret = [[[kls alloc] init] autorelease];
objc_setAssociatedObject(NSApp, sel, OBJC_ASSOCIATION_RETAIN);
});
return ret;
}
+ (id)getSharedInstance;
{
return objc_getAssociatedObject(NSApp, _cmd);
}
@end
(Codes are not tested yet.)
Then, to make a singleton class, all need to do is like this:
@interface ExampleSignleton : NSObject
{
}
@end
@implementation ExampleSignleton
+ (void)initialize
{
static dispatch_once_t pred;
[SingletonHelper initializeSingletonClass:[self class] onceT:pred];
}
@end
For the problem of using @selector(sharedFoo) as the key, I think there is nothing stops me (an individual programer) to create my own conventions, and, if my conventions are consistent within the scope of a project, it'll be fine.
I have to say that I really don't see the point of using an associated object even in your more complicated case here. You're basically just using associated objects on NSApp as an ugly and dangerous thread-safe substitute for an NSMutableDictionary. Why not just use @synchronized and an NSMutableDictionary, then? Associated objects buy you nothing here: they make sense when you have a value which is, well, associated with another object. It makes no sense to associate singletons with NSApp.
As far as I concern, my method is better in terms of code reuse. With the help of the class SingletonHelper, I need only additional 2 lines of codes to implement singleton on any classes. Of course it does cost something, a self-defined convention that all associated values of NSApp, starting with "shared", are singleton instances within the scope of an application. The trade-off, including little bit speed, is considered worthy.
I don't understand why you think static globals are prettier than associated values with NSApp? Singleton instances, after all, should be only available instances of certain classes within the scope of a running instance of NSApplication. Therefore, conceptually it's acceptable (if not perfectly) to bind those instances with NSApp. It is possible, as you suggested, to use a static global nsmutabledctionary to hold these singleton instances. But it is conceptually redundant. NSApp is like the "document" nod in a HTML dom, it's the root of everything. Is it conceptually clearer for you treat singleton instances "rootless" by using static globals?
What I'm criticizing is two things:
1) That your initial proposal somehow had merit just because it was one step along a path to this universal singleton class. That's illogical. A step along a path does not have merit just because the end of the path does.
2) That associated objects on NSApp are better than static globals.
#1 I don't think needs any further explanation. If it's not obvious to you, then I can't convince you otherwise. The claim is a simple non sequitur.
#2 just makes no sense to me. Here is why I think that a static global is better:
- Works even when NSApp is not yet initialized.
- It's much clearer code.
- It's quite possibly faster, especially if you don't need to be thread safe.
- It will use less memory, since associated objects currently incur a 2kB memory cost for each object that has associated references on it. It's unlikely that anything else will use associated references on NSApp, so you'll cause that cost yourself.
- It works on any version of Mac OS X, not just 10.6+.
- It works for Foundation-only programs.
And for reasons why associated objects are better, I'm coming up completely empty. I can't see a single thing about it that's better.
Your comment that NSApp is the root of everything is nonsensical. You can have perfectly workable Objective-C programs that never have an NSApp. Global variables are how you do this in C. Trying to use HTML concepts in C just makes no sense.
If you can come up with an actual concrete advantage to your approach I'll certainly consider it, but so far it's nothing but handwaving.
https://gist.github.com/943369
+ (id)sharedFoo
{
static dispatch_once_t pred;
static Foo *foo = nil;
dispatch_once(&pred, ^{ foo = [[self alloc] init]; });
return foo;
}
Is not it better to do it like this?
+ (id)sharedFoo
{
static dispatch_once_t pred;
static Foo *foo = nil;
dispatch_once(&pred, ^{ foo = [[Foo alloc] init]; });
return foo;
}
Regards,
SP
For the GCD version, how do we make sure that foo is not in a partially modified while another thread is about to assign new value to it? Could dispatch_once guarantee this?
I assume that primitive types(int,char,pointers i.e.) are assigned in an atomic way but i also remember your statement that access to * any pieces* of shared memory must be synchronized;
So, what is the contract about atomicity of assignments/reads of a variable? Are there any documents,references from Apple?
Thanks
It's me again.
You say that Martin Schuerrer's swizzling version is fine but how do we sure that method_exchangeImplementations is thread-safe with any message call to the method to be swizzled? Would not it be possible that another thread could see half modified pointer to the method and crash?
Thanks
Comments RSS feed for this page
Add your thoughts, post a comment:
Spam and off-topic posts will be deleted without notice. Culprits may be publicly humiliated at my sole discretion.