單例模式算是設計模式中比較簡單的一種吧,設計模式不是隻針對某種程式語言,在C++, Java, PHP等其他OOP語言也有設計模式,筆者初接觸設計模式是通過《漫談設計模式》瞭解的。這本書中是用java寫的,個人感覺拜讀完這本書以後雖然有不理解的地方但還是收穫蠻大的。上面提到依賴注入,控制翻轉的時候,沒大看懂,當學習到Strut,Spring, Hibernate的東西的時候才略懂略懂。不過在23種設計模式裡面單例模式還是算比較好理解的, 那麼在OC中又是怎麼來表示單例模式的呢?下面會結合著lusashi的程式碼,理解一下OC中得單例模式。
首先得了解什麼是單例模式,用大白話說,單例模式就是在程式中這個類只對應著一個例項,這就是單例模式,單例模式一般用全域性靜態物件來實現。下面我們會建立一個生成單例的類SingletonClass,在實現檔案中定義各種方法來實現我們的單例模式。
1.單例模式一般用全域性靜態物件來實現,所以我們在SingletonClass.m中定義一個靜態全域性變數是少不了的
1 2 |
//定義靜態全域性變數 static SingletonClass *single = nil; |
2.上面的靜態變數是定義在實現檔案中的所以是私有的,要想獲取該類的例項得有個getInstance方法來獲取例項,在給靜態變數分配記憶體空間之前首先要判斷是否已經分配過啦,確保單例,如果分配過了就不分配了。
1 2 3 4 5 6 7 8 9 |
//獲取靜態全域性物件 +(id)getInstance { //如果沒有生成物件,則為靜態全域性變數分配記憶體 if (single == nil) { single = [[SingletonClass alloc] init]; } return single; } |
3.為了防止使用者通過alloc和new來例項化物件,因此我們要對類方法allcoWithZone進行重寫
1 2 3 4 5 6 7 8 |
//防止通過alloc或者new來建立新的物件我們要重寫allocWithZone +(id)allocWithZone:(NSZone *)zone { if (single == nil) { single = [[super allocWithZone:zone] init]; } return single; } |
4.為了防止使用者把單例進行深淺拷貝,我們需要重寫copyWithZone方法和mutableCopyWithZone方法,在重寫方法之前我們的單例類必須遵循協議NSCoping和NSMutableCoping協議
遵循協議程式碼如下:
1 2 3 4 5 6 7 8 9 |
@interface SingletonClass : NSObject //單例中獲取單例物件的方法 +(id) getInstance; //單例測試方法 -(void) singletonFunction; @end |
重寫copyWithZone方法
1 2 3 4 5 |
//為了防止通過copy來建立新的例項我們要重寫copyWithZone; -(id)copyWithZone:(NSZone *)zone { return self; } |
重寫mutableCopyWithZone方法
1 2 3 4 |
-(id)mutableCopyWithZone:(NSZone *)zone { return self; } |
5.防止使用者把建立的單例dealloc,我們需要重寫retainCount方法
1 2 3 4 5 |
//重寫retainCount方法,防止被dealloc,返回最大值 -(NSUInteger) retainCount { return NSUIntegerMax; } |
6. 重寫release,autorelease, retain方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//重寫retain,引用計數不變 -(id) retain { return self; } //重寫release -(oneway void) release { } //重寫autorelease -(id) autorelease { return self; } |
至此我們的單例模式基本建立完畢,下面開始我們的測試吧;
在main函式中的程式碼如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//單例模式的測試 SingletonClass *single1 = [SingletonClass getInstance]; SingletonClass *single2 = [SingletonClass new]; SingletonClass *single3 = [[SingletonClass alloc] init]; SingletonClass *single4 = [single1 copy]; SingletonClass *single5 = [single1 mutableCopy]; SingletonClass *single6 = [single1 retain]; [single1 release]; [single1 singletonFunction]; NSLog(@"single_retainCount = %lu", single1.retainCount); //輸出地址 NSLog(@"getInstance single1_P = %p", single1); NSLog(@"new single2_P = %p", single2); NSLog(@"allo single3_P = %p", single3); NSLog(@"copy single4_P = %p", single4); NSLog(@"mutableCopy single5_P = %p", single5); NSLog(@"retain single6_P = %p", single6); |
執行結果如下:
1 2 3 4 5 6 7 8 |
2014-08-07 16:04:44.207 Memory[20664:303] singleton Ps: 我是單例模式中得測試方法!! 2014-08-07 16:04:44.207 Memory[20664:303] single_retainCount = 18446744073709551615 2014-08-07 16:04:44.207 Memory[20664:303] getInstance single1_P = 0x100204690 2014-08-07 16:04:44.208 Memory[20664:303] new single2_P = 0x100204690 2014-08-07 16:04:44.208 Memory[20664:303] alloC single3_P = 0x100204690 2014-08-07 16:04:44.208 Memory[20664:303] copy single4_P = 0x100204690 2014-08-07 16:04:44.209 Memory[20664:303] mutableCopy single5_P = 0x100204690 2014-08-07 16:04:44.209 Memory[20664:303] retain single6_P = 0x100204690 |
單例的地址是不變的。
上面是在非ARC模式下得單例模式,那麼在ARC模式下我們應如何實現我們的單例模式呢,我們下面就會給出ARC下的單例模式,用下面的方法,因沒有重寫alloc,copy等方法,通過alloc還是可以給該物件分配一個新物件的,上面是執行緒不安全的,下面是執行緒安全的:
1 2 3 4 5 6 7 8 |
+ (id)sharedSingleton { static MySingleton *sharedSingleton = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedSingleton = [[self alloc] init]; }); return sharedSingleton; } |
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!