The singleton pattern is appropriate when a system component logically requires only one instance—creating additional instances would be redundant or meaningless. A classic example is CLLocationManager, which interfaces with a single physical hardware unit; multiple manager instances offer no practical benefit.
Common System-Provided Singletons in iOS
UIApplication– Represents the app’s runtimeNSNotificationCenter– Central hub for broadcasting notificationsNSFileManager– Manages file system operationsNSUserDefaults– Handles persistent user preferencesNSURLCache– Caches network responsesNSHTTPCookieStorage– Stores HTTP cookies
Implementing a Robust Singleton in iOS
A proper singleton must ensure that only one instance ever exists. The instance should be created lazily—on first access—and subsequent calls return the same object.
Basic (Thread-Unsafe) Implementation
+ (instancetype)sharedInstance {
static MySingleton *instance;
if (!instance) {
instance = [[MySingleton alloc] init];
}
return instance;
}
This approach works in single-threaded contexts but fails under concurrency: multiple threads might simultaneously pass the null check and create separate instances.
While it's theoretically ideal to prevent external calls to alloc or init, Objective-C’s dynamic nature makes this impractical. Apple’s own singleton classes (e.g., NSUserDefaults) do not override alloc, so developers typically follow suit.
Thread-Safe with @synchronized
+ (instancetype)sharedInstance {
static MySingleton *instance;
@synchronized(self) {
if (!instance) {
instance = [[MySingleton alloc] init];
}
}
return instance;
}
This ansures mutual exclusion during instance creation. However, it incurs unnecessary locking overhead on every call—even after initializasion—impacting performance.
Optimal Approach: dispatch_once
+ (instancetype)sharedInstance {
static MySingleton *instance;
static dispatch_once_t token;
dispatch_once(&token, ^{
instance = [[MySingleton alloc] init];
});
return instance;
}
dispatch_once provides thread-safe, lock-free initialization with zero runtime cost after the first execution. It leverages atomic operations internally:
- Initially,
tokenis 0. - The first thread executes the block and atomical updates
token. - Subsequent threads see the updated token and skip the block entirely.
This mechanism guarantees both correctness and high performance, making it the de facto standard for singleton implementation in modern iOS development.