Objective-C Singleton Pattern (with ARC)
Sometime last year I learned how important singletons can be in the iOS sandbox environment. These objects can be globally instantiated and manipulated without issues (most of the time).
After realizing that the majority of my model classes can be supported via singletons, I decided to do some research into how Apple utilizes their low-level blocks for singleton creation.
If you've developed for and iPhone or iPad app that makes any RESTful calls, you've definitely seen a singleton before, as they are fairly easy to create (and also easy to abuse)—for those of you who haven't, here is a basic example:
+ (instanceType *)sharedInstance {
static instanceType *sharedInstance = nil;
if (sharedInstance == nil) {
sharedInstance = [[instanceType alloc] init];
}
return sharedInstance;
}
Now, there are a few issues with this implementation that you should know about. Firstly, this class method is NOT thread safe, so if multiple threads attempt to access this object at the same time you will present a race condition.
Although Apple has shown this example in previous documentation (iOS 4.0+), you should not utilize this pattern today.
If you would like to use singletons, use dispatch_once()
dispatch_once() solves this threading issue because: (1) it guarantees the block will only be called once for the lifetime of the application, (2) it is thread safe, and (3), due to its low-level concurrency it is faster than other methods such as @synchronous(), etc.
"If called simultaneously from multiple threads, this function waits synchronously until the block has completed."
Here is the better singleton pattern:
+ (instanceType *)sharedInstance {
static instanceType *sharedInstance = nil;
static dispatch_once_t onceToken; // onceToken = 0
dispatch_once(&onceToken, ^{
sharedInstance = [[instanceType alloc] init];
});
return sharedInstance;
}
This is the safest (and most effective) way to create a singleton. There is no possible way to create two instances, and it is 100% thread safe.
Written by Paris Xavier Pinkney
Related protips
1 Response
Hi. I'm using this technique but i have a problem with the instance being deallocated when using Objective-C Automatic Reference Counting.
+ (iCloudKeyValueProxy *)instance {
static iCloudKeyValueProxy *sharedInstance = nil;
static dispatchoncet onceToken; // onceToken = 0
dispatch_once(&onceToken, ^{
sharedInstance = [[iCloudKeyValueProxy alloc] init];
});
return sharedInstance;
}
void iCloudKeyValueProxy_Fetch() {
iCloudKeyValueProxy* proxy = [iCloudKeyValueProxy instance];
[proxy fetch];
}
int iCloudKeyValueProxy_GetInt(NSString* key) {
iCloudKeyValueProxy* proxy = [iCloudKeyValueProxy instance];
NSNumber* nsValue = [proxy.storeLocal objectForKey:key];
return nsValue.intValue;
}
Then when calling Fetch and GetInt I get an error excbadaccess code=1 on the first line of iCloudKeyValueProxy_GetInt.
Any ideas how to make the instance leave on during the entire execution of the app?