Reputation: 96391
In my class Deck i have
static Deck *gInstance = NULL;
+(Deck *) instance {
@synchronized(self) {
if (gInstance == NULL)
gInstance = [[self alloc] init];
}
return (gInstance);
}
and an init method that looks like
-(id) init {
if (gInstance != NULL) {
return self;
}
self = [super init];
if (self) {
// Lots of clever things
}
gInstance = self;
return self;
}
My concern here is mainly whether init
is implemented correctly. Please let me know if what i wrote looks right to you.
Or ... is there a way i can make init
private and prevent people (myself included) from seeing it altogether?
Upvotes: 2
Views: 297
Reputation: 6161
In general your constructor shouldn't enforce singleness. Your instance
method should (which it does). The reason for this is that you may want a singleton of the object as well as the ability to create other instances of the object.
As for the code you provided your init
is not thread safe. It would be possible for two separate threads to assign to gInstance
. The thread that sets it first would leak memory. And other subtle bugs could result. For example if the singleton was some sort of shared datastore the thread that won the race would effectively have its data lost with respect to the rest of the program.
The reason I mention thread safety is that I personally have encountered many bugs related to singletons being used in multithreaded apps in unsafe ways. So only have singleton creation be thread unsafe when you are absolutely sure it won't be an issue.
In terms of how to implement it in a thread safe way I have seen it one of two says:
// first way
+ (Deck *)instance {
static dispatch_once_t onceToken;
static Deck *_shared;
dispatch_once(&onceToken, ^{
_shared = [[Deck alloc] init];
});
return _shared;
}
// second way
+ (Deck *)instance {
static Deck *_shared;
@synchronized(self) {
if (_shared == nil) {
_shared = [[Deck alloc] init];
}
}
return _shared;
}
// init method
- (id)init {
if ((self = [super init])) {
// init stuff
}
return self;
}
Using dispatch_once
requires libdispatch which means a minimum OS of iOS 4.0 or OS X 10.6. Using the @synchronized(self)
should work on OSes prior to that.
Upvotes: 1
Reputation: 28688
That is a kind of odd singleton implementation. My favorite implementation is to use some newer functionality present in GCD.
+ (MyObj*)sharedObject;
{
static dispatch_once_t once;
static MyObj *sharedObj;
dispatch_once(&once, ^ { shared = [[MyObj alloc] init]; });
return shared;
}
I would recommend only doing that, nothing more, nothing less. Enforcing a strict singleton will only end in pain and is generally pointless and an anti-pattern.
As far as if there is anything strictly 'wrong' with your implementation, I believe you'd want to return gInstance
in the initializer when it isn't NULL, not self.
Upvotes: 6