Question

What is the equivalent of java synchronized in objective c? I want to be able to make my singleton method safe, so when it's bein called from 2 different threads, they try to use it 1 by 1.

+(MyObject*) getSharedObject
{
     if(!singleton)
     {
          singleton = [[MyObject alloc] init];
     }
     return singleton;
}
Was it helpful?

Solution

Obj-C has a synchronized construct

-(MyObject*) getSharedObject
{
@synchronized(something)
{
     if(!singleton)
     {
          singleton = [[MyObject alloc] init];
     }
     return singleton;
}
}

returning from within a synchronized block does the 'right' thing

OTHER TIPS

Joshua's answer is correct, but requires that you have an object on which to synchronize. Doing this for a singleton can lead to all sorts of odd race conditions if you're not careful. The standard pattern for a singleton is to initialize it in +initialize, using dispatch_once, which does the right thing:

static MyObject *singleton = nil;

+ (void)initialize {
  static dispatch_once_t pred;
  dispatch_once(&pred, ^{ singleton = [[MyObject alloc] init]; } );
}

- (MyObject&)getSharedObject
{
  return singleton;
}

For synchronising singleton creation, you should use the singleton's class as the object to synchronise on. This is my usual pattern:

+(MyObject*) singleton
{
    static MyObject* singleton = nil;
    @synchronized([MyObject class])
    {
         if(singleton == nil)
         {
             singleton = [[MyObject alloc] init];
         }
    }
    return singleton;
}

Points to note:

  • I've made it a class method. You don't actually have to, it'll work as an instance method.

  • Normally within class methods when referring to the class, you would use self (or [self class] in instance methods). However, that would be wrong here because subclasses would synchronise using a different object to the MyObject class.

  • I have put the return outside of the @synchronize block. It is perfectly OK to return from inside the block, but if you do, you get a spurious clang static analyser warning saying the method might not return a value.


Edit

The above pattern is long since obsolete. It's best to use the dispatch_once pattern

+(MyObject*) singleton
{
    static dispatch_once_t onceToken;
    static MyObject* singleton = nil;

    dispatch_once (&onceToken, ^{
        singleton = [[MyObject alloc] init];
    });
    return singleton;
}

I agree with both answers. But if the idea is to instantiate on demand then I'd go with Joshua's suggestion with a slight modification using double-checked-locking:

if (!singleton)  
   @synchronized(something)  
      if (!singleton)  
         instantiate;

This way you avoid unnecessary locking after the object has been instantiated.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top