單例模式是 iOS 開發中最常見的設計模式之一。系統框架大量採用:UIApplication.sharedApplication、NSFileManager.defaultManager、NSNotificationCenter.defaultCenter 等皆為單例。它讓各模組共享同一實例,避免手動傳遞參考,同時確保資源唯一性。
利用 dispatch_once 保證線程安全且僅初始化一次,程式碼簡潔且為 Apple 官方推薦。
#import <Foundation/Foundation.h> @interface ShareData : NSObject @property (nonatomic, strong) NSString *string; + (instancetype)sharedData; @end
#import "ShareData.h"
@implementation ShareData
+ (instancetype)sharedData {
static ShareData *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
_string = @"123"; // ARC 下無需 autorelease
}
return self;
}
@end
ShareData *data = [ShareData sharedData]; NSLog(@"%@", data.string); // 123 data.string = @"456"; // 其他處取得同一實例 ShareData *data2 = [ShareData sharedData]; NSLog(@"%@", data2.string); // 456
早期專案或需相容舊代碼時,必須手動管理記憶體並覆寫 retain/release/autorelease/allocWithZone:/copyWithZone: 等方法,確保單例不可被釋放或複製。
#import "ShareData.h"
static ShareData *_sharedInstance = nil;
@implementation ShareData
@synthesize string = _string;
+ (id)sharedData {
@synchronized(self) {
if (_sharedInstance == nil) {
_sharedInstance = [[super allocWithZone:NULL] init];
}
}
return _sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedData] retain];
}
- (id)copyWithZone:(NSZone *)zone { return self; }
- (id)retain { return self; }
- (NSUInteger)retainCount { return NSUIntegerMax; }
- (void)release { /* never release */ }
- (id)autorelease { return self; }
- (id)init {
self = [super init];
if (self) { _string = [[NSString alloc] initWithString:@"123"]; }
return self;
}
- (void)dealloc {
[_string release];
[super dealloc];
}
@end
| 場景 | 推薦做法 | 核心機制 |
|---|---|---|
| 現代 ARC 專案 | GCD dispatch_once | 系統保證線程安全、僅執行一次 |
| 非 ARC 舊專案 | @synchronized + 覆寫記憶體管理方法 | 手動鎖定、禁止釋放/複製 |
| Swift 專案 | static let shared = MyClass() | 語言層級保證 lazy + thread-safe |
dispatch_once 區塊外初始化:失去線程安全保證。allocWithZone::[[MyClass alloc] init] 會繞過單例邏輯。