Here is what I have concocted, after poring over the singleton literature. Have I forgotten anything?
@implementation MySingleton
static MySingleton *mySharedInstance = nil;
//called by atexit on exit, to ensure all resources are freed properly (not just memory)
static void singleton_remover()
{
//free resources here
}
+ (MySingleton*) sharedInstance{
return mySharedInstance;
}
+ (void)initialize {
if (self == [MySingleton class]) {
mySharedInstance = [[super allocWithZone:NULL] init];
atexit( singleton_remover );
}
}
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedInstance];
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain
{
return self;
}
- (NSUInteger)retainCount
{
return NSUIntegerMax; //denotes an object that cannot be released
}
- (void)release
{
//do nothing
}
- (id)autorelease
{
return self;
}
which avoids the synchronize lock most of the time
If you want your software to be reliable, avoid constructs that work "most of the time"
http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html
Table 4.1. Double-checked lock
A double-checked lock is an attempt to reduce the overhead of taking a lock by testing the locking criteria prior to taking the lock. Because double-checked locks are potentially unsafe, the system does not provide explicit support for them and their use is discouraged.
A few suggestions (more for Mac Cocoa than iPhone, but it may be useful to other people searching the objective-c tag):
One additional fun pattern:
+ (Foo *)sharedFoo {
static Foo *sharedInstance = NULL;
if (!sharedInstance) {
Foo *temp = [[Foo alloc] init]; //NOTE: This MUST NOT have side effects for it to be threadsafe
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, temp, &sharedInstance)) {
[temp release];
}
}
return sharedInstance;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With