views:

189

answers:

3

Working in C# and Java, I've seen basically one way everybody initializes singletons:

static obj _inst = null;

obj getInstance() {
  if (_inst == null) {
    _inst = new obj();
  }
  return _inst;
}

Now, when I move to Objective-C for the iPhone, whenever I see code samples, I see basically the same thing:

static obj _inst = nil;

+ (obj *) sharedObj {
  if (!_inst) {
    _inst = [[obj alloc] init];
  }
  return _inst;
}

There's a class method +initialize that's called on every class in the Objective-C runtime before it's used. Is there any reason I couldn't use that to create my singletons?

static obj _inst = nil;

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

+ (obj *) sharedObj {
  return _inst;
}

It works just fine when I try it in my code, and it gets rid of checking to see if it exists every time before it's accessed. Is there any reason I shouldn't create singletons this way?

+1  A: 

As far as I'm concerned +initialize is the way to do it. Peter Hosey suggests a couple of other catches (inside -init and -allocWithZone:) to make sure you can't instantiate more than one instance of the class, ever. Thus making it a true singleton class and not just a class with a pointer to a particular instance of itself within it.

Daniel Tull
A: 

Initializing the singleton in +initialize will always allocate the instance. If the instance requires significant resources (including initializarion time which will extend the time before your app becomes responsive at statup) and might not be used, lazy initializarion, as in your examples makes sense.

Barry Wark
except +initialize is called only the first time the class is accessed anyway.
Ed Marty
Good point. I stand corrected.
Barry Wark
Just to point out that there is a case (and it's really an edge case here) that +initialize can be called more than once. Take the example of Class A and Class B being a subclass of Class A. Class A implements +initialize, but Class B doesn't. When +initialize is sent to Class B, because it doesn't implement its own, its superclass (Class A)'s implementation of +initialize is used. And so Class A's +intialize has been called more than once.At any rate, your check in +initialize is enough to stop this affecting you. Just putting it out there for knowledge and completeness. :)
Daniel Tull
A: 

Lazy Initialization all the way!

I prefer this pattern (similar to what you have):

+ (id) sharedInstance {
     static MyObject *sMyObject = nil;
     if (!sMyObject) {
         sMyObject = [[MyObject alloc] init];
     }
     return sMyObject;
}

- (oneway void) release { 
     // no-op
}

There is no need to put this in +(void)initialize for a singleton, since it will only get called when you first attempt to use the class.

jarjar
I would prefer to put it in the initialize method, because then I don't have to check if (!sMyObject) every time the sharedInstance is accessed.
Ed Marty
The (!isMyObject) is such a lightweight operation, literally a cmp/jmp instruction on the CPU. I agree you shouldn't be calling [MyObject sharedInstance] every time either.MyObject *obj = [MyObject sharedInstance];[obj blah];[obj setColor: [NSColor greenColor]];[obj setName: @"Hola"];
jarjar