Skip to content

Singletons in Cocoa/Objective-C

I’ll preface this post with the standard advice: Don’t create singletons if you don’t absolutely have to. In general, if you’re creating a global “manager” object of some sort, you’re doing something wrong.

That said, there’s still occasionally a reason to have such a global singleton, such as a “default something.” The sample code in the Cocoa Fundamentals Guide goes to a lot more trouble than it needs to in order to ensure that a class is a singleton.

This is almost never what you want.

First off, you probably want your class to be testable in a variety of configurations. In your unit tests, instead of getting your shared singleton instance in your -setUp method and “resetting” its state in -tearDown, you’d be better off just instantiating a new instance in -setUp and releasing it in -tearDown.

Also, the example in the Cocoa Fundamentals Guide does a lot of work that it simply doesn’t need to. This is all you really need to do to create a singleton in Cocoa:

@interface SomeManager : NSObject
+ (id)sharedManager;
@end

@implementation SomeManager

+ (id)sharedManager {
    static id sharedManager = nil;

    if (sharedManager == nil) {
        sharedManager = [[self alloc] init];
    }

    return sharedManager;
}

@end

That’s it! The astute reader will notice, of course, that this isn’t thread-safe. I got rid of the @synchronized (self) because it won’t do the right thing; depending on what actual class is sent +sharedManager, the value of self will be different!

For the sake of argument, though, let’s say that you do want a singleton with which you can interact from multiple threads at once. One way to do this would be to create your singleton instance in +initialize since it will always be run, on a single thread, before any other methods in your class:

@implementation SomeManager

static id sharedManager = nil;

+ (void)initialize {
    if (self == [SomeManager class]) {
        sharedManager = [[self alloc] init];
    }
}

+ (id)sharedManager {
    return sharedManager;
}

@end

By doing this, you avoid the performance bottleneck of @synchronized taking a recursive lock every time +sharedManager is invoked.

If you want to get fancier, and it’s OK to temporarily have more than one instance of your singleton created, you could even use objc_atomicCompareAndSwapGlobalBarrier to assign the value to return from +sharedManager, though this is probably also more work than it’s worth; after all, +initialize will only be invoked once for your class. (Though it can be re-invoked as a side-effect of initializing subclasses, hence the if (self == [SomeManager class]) { } idiom.)

In all of the above cases, you’ve done a whole lot less work than the example in the Cocoa Fundamentals Guide, and your code is a lot more likely to be correct as a result.

{ 16 } Comments

  1. Clark Cox | June 17, 2009 at 9:07 pm | Permalink

    Another way to make a singleton, that is still lazily loaded, thread-safe and only incurs the cost of synchronization once (i.e. it’s like a double-checked lock, except that it actually works):

    @implementation Foo
    
    static id sharedInstance;
    
    +(id)sharedInstance {
        @synchronized(self) {
            if(!sharedInstance) {
                sharedInstance = [[self alloc] init];
                class_replaceMethod(object_getClass(self),
                    @selector(sharedInstance),
                    [self methodForSelector: @selector(sharedInstance2)],
                    "@@:");
            }
        }
    
        return sharedInstance;
    }
    
    +(id)sharedInstance2 {
        return sharedInstance;
    }
    
    @end
    
  2. Clark Cox | June 17, 2009 at 9:13 pm | Permalink

    (Of course, that doesn’t address the subclassing issue that you mentioned)

  3. eschaton | June 17, 2009 at 9:21 pm | Permalink

    Yeah; using @synchronized (self) in a class method that could be invoked on a subclass is risky.

    I reformatted your code into Markdown, since it didn’t survive the HTML editor widget thingy.

  4. Mo Ayazifar | June 29, 2009 at 1:22 pm | Permalink

    Then finally which one is gonna be the best one regarding to performance? and how are we supposed to use them form outside? is there any sample code available for that?

  5. eschaton | July 6, 2009 at 1:20 pm | Permalink

    You really shouldn’t need to be worried about performance of singleton objects.

  6. scott lewis | September 27, 2009 at 3:53 am | Permalink

    correct me if I’m wrong, but there seems to be a typo in the very first example as the static declaration is inside the class method, which means it will always be set to nil, and thus not really work as a “somewhat” singleton. Is that correct?

  7. Kaelin | October 6, 2009 at 5:27 pm | Permalink

    GCD now offers the possibility of doing this with dispatch_once(). This is almost certainly the most performant technique that’s both thread-safe and concise:

    • (id)sharedInstance; { static id sharedInstance = nil; static dispatch_once_t once = 0; dispatch_once(&once, ^ { sharedInstance = [[self alloc] init]; }); return sharedInstance; }
  8. Dustin L. Howett | January 23, 2010 at 12:35 pm | Permalink

    There’s actually no way for +initialize to be called with a self that isn’t the class +initialize belongs to, by the runtime. The runtime calls initialize in reverse order for the entire superclass tree (assuming that class has not already been initialized) and does not call “[super initialize].” +initialize is called once and only once for every class, as noted in the Apple documentation. The if(self == [SomeManager class]) guard is therefore unnecessary.

  9. Dustin L. Howett | January 23, 2010 at 12:46 pm | Permalink

    Amending my last comment: “Except for the case in which a subclass of yours does not provide +initialize.”

  10. bangnoise | February 1, 2010 at 3:32 am | Permalink

    But your singleton isn’t a singleton at all – you can [[SomeManager alloc] init] as many instances as you like. The point of the Apple way which overrides allocWithZone: is to enforce singleton behaviour – if that’s not important to a singleton class, it maybe doesn’t need to be a singleton anyway.

    @synchronized([SomeManager class]) { }

    Is an improvement on Apple’s example locking, I think..?

  11. Fred McCann | May 21, 2010 at 2:40 pm | Permalink

    I’ve written up an in-depth discussion of the singleton pattern here:

    http://www.duckrowing.com/2010/05/21/using-the-singleton-pattern-in-objective-c/

  12. Otto Schnurr | September 28, 2010 at 10:54 am | Permalink

    @scott: When a static variable is declared inside a function, it’s only initialized the first time the function is executed.

  13. Charles Parnot | August 19, 2011 at 2:08 pm | Permalink

    Is this thread-safe?

    @implementation Foo
    
    static id sharedInstance;
    
    +(id)sharedInstance
    {
        if (sharedInstance)
            return sharedInstance;
    
        @synchronized(self)
        {
            if (!sharedInstance)
                sharedInstance = [[self alloc] init];
        }
        return sharedInstance;
    }
    
    @end
    
  14. Shea Ako | October 21, 2011 at 9:16 am | Permalink

    I’ve run into a situation that demonstrates that the example published here is not actually thread safe.

    Two threads call +sharedManager at (more or less) the same time. The earlier call to +sharedManager triggers +initialize on its thread, but before +initialize completes the second thread executes +sharedManager.

    When +sharedManager is called on the second thread it can return nil if +initialize hasn’t finished yet on the first thread.

    Using some sort of locking is necessary for thread safety.

    I use a lock in +sharedManager.around

       if (sharedManager == nil) {...}
    
  15. Shea Ako | October 21, 2011 at 9:18 am | Permalink

    addendum to my previous comment – I meant to say,

    I use the first method described in the article and put a lock around:

       if (sharedManager == nil) {...}
    
  16. Carlo | December 15, 2011 at 5:14 pm | Permalink

    This is very very interesting. I’m in the situation that I want to create a global “manager” to manage Core Data (all the methods to access Core Data in the delegate make me really uncomfortable). Now I’m wondering: what is the right thing to do if singleton is bad?

Post a Comment

Your email is never published nor shared. Required fields are marked *