單例模式確保進程中僅存在一個類實例,iOS 系統框架大量採用(NSFileManager、UIApplication 等)。本文提供 ARC 與非 ARC 兩套生產級實現,涵蓋線程安全、複製/釋放攔截、區域分配攔截等關鍵細節。
dispatch_once 保證初始化僅執行一次+allocWithZone: 返回共享實例retain/release/autorelease/retainCount/copyWithZone:[[Singleton alloc] init] 創建第二個實例#import@interface Singleton : NSObject + (instancetype)sharedInstance; @end
#import "Singleton.h"
@implementation Singleton
+ (instancetype)sharedInstance {
static Singleton* _sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[super allocWithZone:NULL] init];
});
return _sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
// 初始化業務屬性
}
return self;
}
// 核心攔截:所有分配路徑導向 sharedInstance
+ (id)allocWithZone:(struct _NSZone*)zone {
return [self sharedInstance];
}
// 複製返回自身
- (id)copyWithZone:(struct _NSZone*)zone {
return self;
}
// 禁止釋放(ARC 下通常不需實現,保留以防手動釋放)
- (void)dealloc {
// 單例通常不釋放,若需清理資源可在這裡處理
}
@end
#import "Singleton.h"
@implementation Singleton
+ (instancetype)sharedInstance {
static Singleton* _sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[super allocWithZone:NULL] init];
});
return _sharedInstance;
}
+ (id)allocWithZone:(NSZone*)zone {
return [[self sharedInstance] retain]; // 非 ARC 需 retain 平衡
}
- (id)copyWithZone:(NSZone*)zone {
return self;
}
- (id)retain {
return self; // 單例永不釋放,retain 無效
}
- (NSUInteger)retainCount {
return UINT_MAX; // 標記為不可釋放
}
- (void)release {
// 故意空實現,防止釋放
}
- (id)autorelease {
return self;
}
- (instancetype)init {
self = [super init];
if (self) {
// 初始化業務屬性
}
return self;
}
- (void)dealloc {
// 單例不應走到這裡,但保留超類調用以防萬一
[super dealloc];
}
@end
| 機制 | ARC 版 | 非 ARC 版 |
|---|---|---|
| allocWithZone 返回 | 直接返回 sharedInstance | 返回 [sharedInstance retain] |
| retain/release/autorelease | 由編譯器管理,通常不需覆寫 | 必須覆寫全部,retainCount=UINT_MAX |
| copyWithZone | 返回 self | 返回 self |
| dealloc | 可選實現清理 | 調用 [super dealloc] |
+initialize 中創建實例(可能被調用多次,且子類會繼承調用)@synchronized(self) 替代 dispatch_once(效能差且易死鎖)retainCount 返回 UINT_MAX,否則自動釋放池可能過度釋放+destroyInstance 手動清理(罕見需求)掌握雙環境單例實現,能讓你在新舊專案中游刃有餘,編寫出線程安全、記憶體正確、符合 Cocoa 規範的單例類。