11

Hi I had an implementation previous versions of iOS for a singleton as follows:

.h file

@interface CartSingleton : NSObject 
{

}
+(CartSingleton *) getSingleton;

.m file

@implementation CartSingleton

static CartSingleton *sharedSingleton = nil;

+(CartSingleton *) getSingleton
{
    if (sharedSingleton !=nil)
       {
        NSLog(@"Cart has already been created.....");
        return sharedSingleton;
       }
    @synchronized(self)
   {
    if (sharedSingleton == nil)
       {
        sharedSingleton = [[self alloc]init];
        NSLog(@"Created a new Cart");
       }
   }
    return sharedSingleton;
}
//==============================================================================
+(id)alloc
{
    @synchronized([CartSingleton class])
   {
    NSLog(@"inside alloc");
    NSAssert(sharedSingleton == nil, @"Attempted to allocate a second instance of a singleton.");
    sharedSingleton = [super alloc];
    return sharedSingleton;
   }

    return nil;
}

//==============================================================================
-(id)init
{
    self = [super init];
}

However on the web I see people have implemented the Singleton design pattern using this code:

+ (id)sharedInstance
{
  static dispatch_once_t pred = 0;
  __strong static id _sharedObject = nil;
  dispatch_once(&pred, ^{
    _sharedObject = [[self alloc] init]; // or some other init method
  });
  return _sharedObject;
}

Could someone who is experience please guide me. Im a newbie and thoroughly confused between the old iOS implementation of the Singleton and the new one and which is the correct one?

Thanks a lot

Pang
  • 9,564
  • 146
  • 81
  • 122
banditKing
  • 9,405
  • 28
  • 100
  • 157
  • See http://stackoverflow.com/questions/5720029/create-singleton-using-gcds-dispatch-once-in-objective-c for the more modern one, simpler but still thread safe. – Joachim Isaksson Jan 09 '12 at 23:18

3 Answers3

19

Strictly speaking, you must use:

+ (MySingleton*) instance {
     static dispatch_once_t _singletonPredicate;
     static MySingleton *_singleton = nil;

     dispatch_once(&_singletonPredicate, ^{
        _singleton = [[super allocWithZone:nil] init];
     });

     return _singleton;
 }

 + (id) allocWithZone:(NSZone *)zone {
      return [self instance];
 }

Now you guarantee that one cannot call alloc/init and create another instance.

Explanation: The instance method is at the class level and is your main access method to get a reference to the singleton. The method simply uses the dispatch_once() built-in queue that will only execute a block once. How does the runtime guarantee that the block is only executed once? Using the predicate you supply (of type dispatch_once_t). This low-level call will guarantee that even if there are multiple threads trying to call it, only one succeeds, the others wait until the first one is done and then returns.

The reason we override allocWithZone is because alloc calls allocWithZone passing nil as the zone (for the default zone). To prevent rogue code from allocating and init-ializing another instance we override allocWithZone so that the instance passed back is the already initialized singleton. This prevents one from creating a second instance.

Καrτhικ
  • 3,833
  • 2
  • 29
  • 42
  • 1
    Can someone explain this code in a bit more detail to improve the answer? – djskinner Aug 12 '12 at 21:47
  • Hope the explanation helps. Otherwise please ask a specific question for clarification. – Καrτhικ Aug 20 '12 at 15:07
  • I don't think you need allocWithZone - there are many such "holes" in the single method, and Apple suggests at WWDC to just do the first method and forget all the boilerplate overrides to try and catch "cheaters". My recollection anyway. – David H Mar 12 '13 at 19:53
9

The dispatch_once snippet is functionally identical to other one. You can read about it at http://developer.apple.com/library/mac/#documentation/Darwin/Reference/Manpages/man3/dispatch_once.3.html.

This is what I use for singletons:

+ (MySingleton*) getOne {
    static MySingleton* _one = nil;

    @synchronized( self ) {
        if( _one == nil ) {
            _one = [[ MySingleton alloc ] init ];
        }
    }

    return _one;
}

NOTE: In most cases, you do not even need to use @synchronized (but it is safe this way).

taber
  • 3,166
  • 4
  • 46
  • 72
Andrei Tchijov
  • 559
  • 5
  • 11
  • If you don't use @syncrhonized elsewhere, this pulls in a huge amount of overhead to handle ObjectiveC exceptions - so if you are not using them, you should use the selected answer and the block version. – David H Mar 12 '13 at 19:51
0

A singleton is a special kind of class where only one instance of the class exists for the current process. (In the case of an iPhone app, the one instance is shared across the entire app.) Some examples in UIKit are [UIApplication sharedApplication] (which returns the sole instance of the application itself), and [NSFileManager defaultManager] (which returns the file manager instance). Singletons can be an easy way to share data and common methods across your entire app.

Rather than create instances of the singleton class using alloc/init, you'll call a class method that will return the singleton object. You can name the class method anything, but common practice is to call it sharedName or defaultName.

Please check a link with best answer :http://www.idev101.com/code/Objective-C/singletons.html

sarit bahuguna
  • 875
  • 8
  • 8