views:

260

answers:

3

Which one synchronization method to use to ensure a singleton remains a singleton?

+(Foo*)sharedInstance
{
   @synchronized(self)
   {
      if (nil == _sharedInstance)
      {
         _sharedInstance = [[Foo alloc] init];
         ...
      }
   }
   return _sharedInstance;
}

or using a mutex?

#import <pthread.h>

static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;

+(Foo*)sharedInstance
{
   pthread_mutex_lock(&_mutex);
   if (nil == _sharedInstance)
   {
      _sharedInstance = [[Foo alloc] init];
      ...
   }
   pthread_mutex_unlock(&_mutex);
   return _sharedInstance;
}

Hmmm.. any comments on this?

+1  A: 

This CocoaDev page can be useful for your need.

Laurent Etiemble
Thanks. Hmm.. I did not think about the possibility to retain or overrelease a singleton. Hell, who does such things? :)
MacTouch
+2  A: 

The fastest thread safe way to do this is with Grand Central Dispatch ( libdispatch ) and dispatch_once()

+(MyClass *)sharedInstance
{   
    static MyClass *sharedInstance = nil;
    static dispatch_once_t pred;

    dispatch_once(&pred, ^{
        sharedInstance = [[MyClass alloc] init];
    });

    return sharedInstance;
}
Colin Wheeler
+5  A: 

Keep in mind that for both Colin's and Harald's otherwise correct answers, there is a very subtle race condition that could lead you to a world of woe.

Namely, if the -init of the class being allocated happens to call the sharedInstance method, it will do so before the variable is set. In both cases it will lead to a deadlock.

This is the one time that you want to separate the alloc and the init. Cribbing Colin's code because it is the best solution (assuming Mac OS X):

+(MyClass *)sharedInstance
{   
    static MyClass *sharedInstance = nil;
    static dispatch_once_t pred;

    if (sharedInstance) return sharedInstance;

    dispatch_once(&pred, ^{
        sharedInstance = [MyClass alloc];
        sharedInstance = [sharedInstance init];
    });

    return sharedInstance;
}

note this only works on Mac OS X; Snow Leopard, in particular. Blocks aren't available on the iPhone. On that platform, use a lock or one of the various means of doing something once that isn't blocks based.

bbum
Thanks for this one, although it took me half an hour to find the correct reference to the blocks (^) syntax http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/Blocks/Blocks.pdf, which for some reason is not included in their Objective C documentation
Harald Scheirich
Thanks. It was the first thing too I was thinking about while seeing your answer. I did not know there is a possibility to write such blocks in objective c (like anonymous class implementation in Java or delegates in C#). This is the answer for my other problem here: http://stackoverflow.com/questions/2118728/method-signature-for-a-selectorInstead of using callbacks I now use blocks. :)Perhaps, I initialize my singleton in the AppDelegate and actually don't care about thread concurrency. The instance is simple there, when needed. It is a kind of cache for few things like images etc.
MacTouch