EDIT
I include this at the top, below you can see my historical background questions and implementation. However, I think I have found the best way to provide a sharedInstance method without the overhead of locking, I would like to hear potential concerns about this:
// Volatile to make sure we are not foiled by CPU caches static volatile ALBackendRequestManager *sharedInstance; // There no need to call this directly, as method swizzling in sharedInstance // means this will get called after the singleton is initialized. + (MySingleton *)simpleSharedInstance { return (MySingleton *)sharedInstance; } + (MySingleton*)sharedInstance { @synchronized(self) { if (sharedInstance == nil) { sharedInstance = [[MySingleton alloc] init]; // Replace expensive thread-safe method // with the simpler one that just returns the allocated instance. SEL orig = @selector(sharedInstance); SEL new = @selector(simpleSharedInstance); Method origMethod = class_getClassMethod(self, orig); Method newMethod = class_getClassMethod(self, new); method_exchangeImplementations(origMethod, newMethod); } } return (MySingleton *)sharedInstance; }
And the historical discussion around initialization:
Now I see that the source code was more like mine (below), except for checking the instance out of lock.
Although the new initialization method + (void) is interesting, I'm not sure if I like it better. It seems that now, to get a singleton instance, you should now always call:
MySingleton instance = [[MySingleton alloc] init];
It is not right? Is this weird and more effective if the call to initialize is already blocked for you? The double blocking method seems to work fine for this use case, and also avoids blocking (at the potential cost of double placement, I think, since more than one thread might fail through if).
Another thing that seems strange is if the initialize method was really preferable, why don't we see it elsewhere? Objective-C has existed for a long time, and I fear the underlying mechanisms that differ from almost all published examples.
My code that I am currently using (which reflects what I saw elsewhere, including this answer):
+ (MySingleton *)sharedInstance { @synchronized(self) { if (sharedInstance == nil) sharedInstance = [[MySingleton alloc] init]; } return sharedInstance; } + (id)allocWithZone:(NSZone *)zone { @synchronized(self) { if (sharedInstance == nil) { sharedInstance = [super allocWithZone:zone]; return sharedInstance; // assignment and return on first allocation } } return nil; // on subsequent allocation attempts return nil }