Hi Ben,
 
>I'm rather confused by the commonly used implementation of singletons. 
>(Ignoring the fact that perhaps I shouldn't be using singletons) I would 
>appreciate you view on this.
>
>Normally I implement a singleton such as..
>
>static MyClass *sharedInstance = nil;
>+ (MyClass *)sharedInstance
>{
>       @synchronized(self)
>    {
>               if (sharedInstance == nil)
>                       sharedInstance = [[self alloc] init];
>   }
>       return(sharedInstance);
>}

The above will still work in an ARC environment. It is rather inefficient, 
however. For details please check the "Double Check Locking Optimization 
pattern":
http://www.cs.wustl.edu/~schmidt/PDF/DC-Locking.pdf

The reason it is inefficient is that locking (mutexes, or @synchronized above) 
is expensive. And you incur that expense every single time you call 
sharedInstance method.

A better way to write that method is below:


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

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

  return sharedInstance;
}

The above is a lot more efficient. It does not incur the cost of locking 
(mutex, or @synchronized) every single time. It is thread safe. Read the paper 
for detailed analysis.

>This has fared me well over the years.
>
>With the introduction of ARC, I assumed there might be a more suitable 
>implementation out there, and I found this common snippet of code commonly on 
>the net.
>
>+ (MyClass *)sharedInstance
>{
>    static MyClass *sharedInstance = nil;
>   static dispatch_once_t onceToken;
>    dispatch_once(&onceToken, ^{
>        sharedInstance = [[MyClass alloc] init];
>        // Do any other initialisation stuff here
>    });
>    return sharedInstance;
>}

Yes, the above looks correct.

>Which confuses me because surely it should look more like.
>
>static MyClass *sharedInstance = nil;
>+ (MyClass *)sharedInstance
>{
>   if(sharedInstance==nil){
>    static dispatch_once_t onceToken;
>    dispatch_once(&onceToken, ^{
>        sharedInstance = [[MyClass alloc] init];
>        // Do any other initialisation stuff here
>    });
>}
>    return sharedInstance;
>}
>
>...else otherwise the second time I access the singleton, MyClass * 
>sharedInstance is declared a second time and set to nill, removing the first 
>instance from memory under ARC?

No, the second time sharedInstance is called it will NOT be set to nil. This is 
more of a C/C++ detail. It will not be set to nil again because the variable is 
static.


try the following in Xcode and you will see :-)

-(void) callMe
{
  static int i = 0;

  NSLog(@"value before increment is: %d, i);

  ++i;

  NSLog(@"value after increment is: %d, i);
}

Invoke "callMe" several times and you will see that it keeps incrementing i. So 
you will see


value before increment is: 0
value after increment is: 1
value before increment is: 1
value after increment is: 2
value before increment is: 2
value after increment is: 3

Thanks,
Abdul
_______________________________________________

Cocoa-dev mailing list ([email protected])

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to