單例模式是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱為單例類的特殊類。通過單例模式可以保證系統(tǒng)中一個類只有一個實例而且該實例易于外界訪問,從而方便對實例個數(shù)的控制并節(jié)約系統(tǒng)資源。如果希望在系統(tǒng)中某個類的對象只能存在一個,單例模式是最好的解決方案。
在Java中我們定義一個單例類:
- <span style="font-size:12px;">public class Singleton {
- private static Singleton uniqueInstance = null;
-
- private Singleton() {
-
- }
-
- public static Singleton getInstance() {
- if (uniqueInstance == null) {
- uniqueInstance = new Singleton();
- }
- return uniqueInstance;
- }
-
- }</span>
在ios中我們按照java那樣定義一個單例類,
- <span style="font-size:12px;">static DataModel *_sharedDataModel=nil;
-
- @implementation DataModel
-
-
- +(DataModel *)sharedDataModel
- {
-
-
- if (!_sharedDataModel)
- {
-
- _sharedDataModel=[[self alloc] init];
-
-
- }
-
-
-
-
- return _sharedDataModel;
-
- }
-
-
-
-
-
-
-
- @end
- </span>
- <span style="font-size:12px;"> DataModel *model1=[[DataModel alloc] init];
-
-
- DataModel *model2=[DataModel sharedDataModel];
-
-
-
- NSLog(@"model1:%@",model1);
-
- NSLog(@"model2:%@",model2);
- </span>
打印內存地址,我們發(fā)現(xiàn)內存地址不一樣,也就是說它們并沒有共用一個內存,
- <span style="font-size:12px;">2014-02-24 14:31:57.734 IOSStudy[833:a0b] model1:<DataModel: 0x8e24600>
- 2014-02-24 14:31:57.735 IOSStudy[833:a0b] model2:<DataModel: 0x8e24610></span>
顯然在ios中這樣定義單例類是不對的,查相關資料,發(fā)現(xiàn)
在objective-c中要實現(xiàn)一個單例類,至少需要做以下四個步驟:
1、為單例對象實現(xiàn)一個靜態(tài)實例,并初始化,然后設置成nil,
2、實現(xiàn)一個實例構造方法檢查上面聲明的靜態(tài)實例是否為nil,如果是則新建并返回一個本類的實例,
3、重寫allocWithZone方法,用來保證其他人直接使用alloc和init試圖獲得一個新實力的時候不產(chǎn)生一個新實例,
4、適當實現(xiàn)allocWitheZone,copyWithZone,release和autorelease。
疑問來了,allocWithZone是什么,和alloc有什么區(qū)別,為什么要重寫這個方法,查相關資料得知
在NSObject 這個類的官方文檔里面,allocWithZone方法介紹說,該方法的參數(shù)是被忽略的,正確的做法是傳nil或者NULL參數(shù)給它。而這個方法之所以存在,是歷史遺留原因。
Do not override allocWithZone: to include any initialization code. Instead, class-specific versions of init… methods.
This method exists for historical reasons; memory zones are no longer used by Objective-C.
文檔里面提到,memory zone已經(jīng)被棄用了,只是歷史原因才保留這個接口。詳細是什么歷史原因我沒找到,不過后面介紹的內容會稍微涉及到。
而實踐證明,使用alloc方法初始化一個類的實例的時候,默認是調用了 allocWithZone 的方法。于是覆蓋allocWithZone方法的原因已經(jīng)很明顯了:為了保持單例類實例的唯一性,需要覆蓋所有會生成新的實例的方法,如果有人初始化這個單例類的時候不走[[Class alloc] init] ,而是直接 allocWithZone, 那么這個單例就不再是單例了,所以必須把這個方法也堵上。
那么下面我們看看如何正確定義一個單例類:
- static DataModel *_sharedDataModel=nil;
-
- @implementation DataModel
-
-
- +(DataModel *)sharedDataModel
- {
-
-
- @synchronized(self)
- {
-
- if (_sharedDataModel==nil)
- {
-
-
- [[self alloc] init];
- }
-
-
- return _sharedDataModel;
-
- }
-
- return _sharedDataModel;
-
- }
-
-
-
- +(id) allocWithZone:(struct _NSZone *)zone
- {
-
-
- @synchronized(self)
- {
-
- if (_sharedDataModel==nil)
- {
-
- _sharedDataModel=[super allocWithZone:zone];
-
- return _sharedDataModel;
- }
-
-
-
-
- }
-
- return nil;
-
-
- }
-
-
- -(id) copy
- {
-
-
- return self;
-
- }
-
-
-
- -(id) retain
- {
-
-
- return self;
-
-
- }
-
- -(unsigned) retainCount
- {
-
-
- return UINT_MAX;
-
-
- }
-
-
- -(oneway void) release
- {
-
-
-
- }
-
-
- -(id) autorelease
- {
-
-
- return self;
-
- }
- DataModel *model1=[[DataModel alloc] init];
-
-
- DataModel *model2=[DataModel sharedDataModel];
-
-
- DataModel *model3=[model1 copy];
-
- NSLog(@"model1:%@",model1);
-
- NSLog(@"model2:%@",model2);
-
- NSLog(@"model3:%@",model3);
- 2014-02-24 15:31:53.017 IOSStudy[1114:a0b] model1:<DataModel: 0xa063c30>
- 2014-02-24 15:31:53.018 IOSStudy[1114:a0b] model2:<DataModel: 0xa063c30>
- 2014-02-24 15:31:53.019 IOSStudy[1114:a0b] model3:<DataModel: 0xa063c30>
我們看打印結果,內存地址一樣,說明DataModel類只初始化一次
貌似在ARC模式下,還有這種方式
- @implementation DZSinglonARC
- + (DZSinglonARC*) shareInstance
- {
- static DZSinglonARC* share = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- share = [[super allocWithZone:NULL] init];
- });
- return share;
- }
- + (instancetype) allocWithZone:(struct _NSZone *)zone
- {
- return [self shareInstance];
- }
- @end
如果還有其他的一些定義單例類的方式,大家可以說出來,相互學習~~~~
|