首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Objective-C 單例模式完整實現:ARC 與非 ARC 環境雙版本詳解

     編輯:關於C語言

Objective-C 單例模式完整實現:ARC 與非 ARC 環境雙版本詳解

單例模式確保進程中僅存在一個類實例,iOS 系統框架大量採用(NSFileManager、UIApplication 等)。本文提供 ARC 與非 ARC 兩套生產級實現,涵蓋線程安全、複製/釋放攔截、區域分配攔截等關鍵細節。

核心設計原則

  1. 線程安全:使用 dispatch_once 保證初始化僅執行一次
  2. 防止外部分配:重寫 +allocWithZone: 返回共享實例
  3. 攔截複製/釋放:非 ARC 下覆寫 retain/release/autorelease/retainCount/copyWithZone:
  4. 私有化 init:防止 [[Singleton alloc] init] 創建第二個實例

ARC 環境實現(推薦,現代專案標配)

介面檔 Singleton.h

#import 

@interface Singleton : NSObject

+ (instancetype)sharedInstance;

@end

實現檔 Singleton.m

#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

非 ARC 環境實現(維護舊專案必備)

#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]

進階話題:單例的替代方案

  • 依賴注入:將單例作為參數傳遞,便於單元測試與解耦
  • 協議導向:定義協議,單元測試時注入 Mock 實現
  • 工廠模式:由工廠控制實例生命週期,而非類自身強制單例

避坑清單

  1. 不要在 +initialize 中創建實例(可能被調用多次,且子類會繼承調用)
  2. 不要用 @synchronized(self) 替代 dispatch_once(效能差且易死鎖)
  3. 非 ARC 下務必實現 retainCount 返回 UINT_MAX,否則自動釋放池可能過度釋放
  4. 若單例持有大量資源,考慮提供 +destroyInstance 手動清理(罕見需求)
  5. 掌握雙環境單例實現,能讓你在新舊專案中游刃有餘,編寫出線程安全、記憶體正確、符合 Cocoa 規範的單例類。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved