開發設計模式——單例模式

我們常見的設計模式,大致可以分爲以下三類:創建型、結構性、行爲型。今天我們要說的單例模式,屬於三種類型當中的創建型。


在開始之前呢,我們需要搞懂一個問題,就是我們爲什麼要用單例,它產生的背景是怎麼樣的呢?其實這與我們的開發習慣有很大關係。


在xcode 4.2之前我們一直是手動分配和釋放內存,也就是MRC,每當我們要銷燬實例,都要手動release去釋放內存,但是這步操作我們經常會忘記,這個問題一直困擾着開發開發人員,即使是很注意了也不能完全避免。


xcode 4.2之後引入了ARC機制,系統可以自己去管理內存了,以前釋放的工作,不再需要我們手動去操作,這給開發人員省了不少事。但ARC同時也存在一個問題,就是要銷燬的對象,我們並不知道它是何時去釋放,換句話說,對象並不會馬上釋放,這個操作會有一定延時。在創建對象較多,將被銷燬的對象沒有馬上釋放的情況下,系統的性能就會受到一定影響。


說到這裏我想大家多少明白了,在ARC機制下,對象沒有被馬上釋放,我們只有通過儘可能少的創建實例對象的方式,去減少性能上的消耗,同時,在程序的不同的地方,我們可能需要用到同一個對象,並且他的屬性和接口都不會改變,爲了避免創建多個重複的對象,單例模式誕生了。


設計模式不是某種語言的標準和規範,它之所以被設計出來,是因爲經過大量的實踐,人們產生了這樣的需求,爲了滿足自己的需求,我們才設計出了各種各樣的設計模式。


廢話說的差不多了,接下來我們就來看看它有什麼特點。


第一個特點:必須有且只有一個實例,它是全局唯一的

第二個特點:必須自行創建一個實例

第三個特點:必須提供一個全局接口,暴露給外部使用


具體的實現思路是怎麼樣的呢?


首先,要提供一個靜態實例,一般情況下設置爲nil,不僅是OC,在Swift、Java中也是如此,其次,要提供一個方法創建單例,如果單例存在就返回,如果不存在就創建,然後,在OC裏面重寫父類中的allocWithZone方法,保證是一個單例,當我們在調用alloc的時候會調用該方法,最後,根據實際情況,重寫父類copyWithzone等等......

首先我們來實現一個非線程安全的單例:

static RCMailViewController *instance = nil;

+ (instancetype)sharedInstance {
    if (instance == nil) {
        instance = [[RCMailViewController alloc] init];
    }
    return instance;
}

+(id)allocWithZone:(struct _NSZone *)zone {
    if (instance == nil) {
        instance = [super allocWithZone:zone];
    }
    return instance;
}

在確定只有一個線程的時候,用這種不寫法是沒有問題的,但是現在絕大部分程序都是多線程,這種寫法就有問題了。

多線程的時候,爲了確保線程安全,我們一般這樣寫:

static RCMailViewController *instance = nil;

+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (instance == nil) {
	instance = [[RCMailViewController alloc] init];
        }
    });
    return instance;
}

+(id)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (instance == nil) {
            instance = [super allocWithZone:zone];
        }
    });
    return instance;
}

其實單裏的實現方式還有很多,比如餓漢式,@synchronized等等,我這裏就不再寫了,最常用的就是用GCD線程安全的方式,並且allocWithZone方法通常可以不寫。
以上這些希望會對你有幫助。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章