說在前面
進入正式的設計模式交流之前,扯點閑話。我們在項目開發的過程中,經常會不經意的使用一些常見的設計模式,如單例模式、工廠方法模式、觀察者模式等,以前做.NET開發的時候,認真拜讀了一下程傑老師的《大話設計模式》,程老師用詼諧的語言,貼近生活的示例,讓我對設計模式有了一個大致的了解。轉型做IOS開發后,一直想閱讀一下針對IOS設計模式方面的書籍,也買了一本《Objective-C編程之道:iOS設計設計模式解析》進行學習,本系列設計模式的文章,有些內容來自這兩本書籍,也有些內容來自於網絡和個人學習過程的整理,算是本人對設計模式學習的筆記,大家對文章中不足的地方,歡迎提出改進的建議。
定義
保證一個類僅有一個實例,並提供一個該實例的全局訪問點。
定義包含三層含義:一是某個類只能有一個實例;二是它必須自行創建這個實例;三是它必須向整個系統提供這個實例。
結構圖
從結構圖可以看到,單例模式(Singleton)是比較獨立的一個設計模式,它的主要特點是控制某個類的實例唯一性,通過上圖我們知道它包含的類只有一個,就是Singleton。該模式中包含一個靜態私有成員變量mySingleton與類方法sharedInstance()。sharedInstance ()方法負責實例化自己,然后存儲在靜態成員mySingleton變量中,以確保只有一個實例被創建。
單例模式的實現
在Objective-C中實現單例模式,需要完成如下四個步驟:
- 第一步:定義一個靜態實例變量mySingleton(名字可以自己取),初始化為nil,代碼如下所示:
1 static MySingleton *mySingleton = nil;
- 第二步:實現一個類方法檢查上面聲明的靜態實例是否為nil,如果是則新建並返回一個本類的實例,代碼如下所示:
1 + (id)sharedInstance 2 { 3 static dispatch_once_t onceToken; 4 dispatch_once(&onceToken, ^{ 5 if(mySingleton == nil) 6 { 7 mySingleton = [[self alloc] init]; 8 } 9 }); 10 return mySingleton; 11 }
【說明】:dispatch_once函數是GCD中的API,它保證應用程序即使在多線程環境下,也只執行一次。當然,也可以使用@synchronize來達到線程安全的目的,代碼如下所示:
1 + (id)sharedInstance 2 { 3 @synchronized (self) 4 { 5 if (mySingleton == nil) 6 { 7 mySingleton = [[self alloc] init]; 8 } 9 } 10 return mySingleton; 11 }
- 第三步:重寫allocWithZone方法,用來保證使用alloc和init試圖獲得一個新實例的時候不產生新實例,代碼如下所示:
1 + (id)allocWithZone:(NSZone *)zone 2 { 3 static dispatch_once_t onceToken; 4 dispatch_once(&onceToken, ^{ 5 if (mySingleton == nil) 6 { 7 mySingleton = [super allocWithZone:zone]; 8 NSLog(@"allocWithZone"); 9 } 10 }); 11 return mySingleton; 12 }
- 第四步:適當實現copyWithZone,release和autorelease等方法。代碼如下所示:
1 // 如果有其他初始化操作,可在這里進行初始化 2 - (id)init 3 { 4 self = [super init]; 5 if (self != nil) 6 { 7 // 其他初始化操作 8 } 9 return self; 10 } 11 12 // 防止外界拷貝造成多個實例,保證實例的唯一性。 13 - (id)copyWithZone:(NSZone *)zone 14 { 15 return self; 16 } 17 18 // 因為只有一個實例對象,所以retain不能增加引用計數。 19 - (id)retain 20 { 21 return self; 22 } 23 24 // 因為只有一個實例對象,設置默認引用計數。這里是取的NSUinteger的最大值,當然也可以設置成1或其他值。 25 - (NSUInteger)retainCount 26 { 27 return UINT_MAX; // denotes an object that cannot be released 28 } 29 30 // oneway是用於多線程編程中,表示單向執行,不能“回滾”,即原子操作。該方法是空的,不讓用戶release掉這個對象。 31 - (oneway void)release 32 { 33 //do nothing 34 } 35 36 //除了返回單例外,什么也不做。 37 - (id)autorelease 38 { 39 return self; 40 } 41 42 // 該方法永遠不會被調用,因為在程序的生命周期內容,該單例一直都存在。(所以該方法可以不實現) 43 - (void)dealloc 44 { 45 [super dealloc]; 46 }
【說明】:對於步驟二和步驟三,也可以按如下方式實現:
1 + (id)sharedInstance 2 { 3 @synchronized(self) 4 { 5 if(mySingleton == nil) 6 { 7 mySingleton = [[super allocWithZone:NULL] init]; 8 NSLog(@"allocWithZone"); 9 } 10 } 11 return mySingleton; 12 } 13 14 // 通過返回當前的sharedInstance實例,就能防止實例化一個新的對象。 15 + (id)allocWithZone:(NSZone *)zone 16 { 17 return [[self sharedInstance] retain]; 18 }
單例模式在IOS中的應用
單例模式在IOS中的應用非常廣泛,如[NSNotificationCenter defaultCenter]、[UIApplication sharedApplication]、[NSFileManager defaultManager]等。