iOS單例模式

單例模式大概是設(shè)計模式種較簡單的一種設(shè)計模式。但在實際的開發(fā)過程中仍然存在一些坑。所以本文總結(jié)了下iOS中的單例模式。

什么是單例模式?

  • ensures a class only has one instance
  • provides a global point of access to it
  • 確保一個類永遠(yuǎn)只有一個實例
  • 提供一個全局的訪問入口訪問這個實例

蘋果官方文檔的一副圖描述了請求普通類和單例的區(qū)別:


請求普通類與單例的區(qū)別

如何實現(xiàn)基本的單例模式?

Singleton *sharedInstance = nil;

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

全局的變量sharedInstance有個缺點,可以被外部隨意修改,為了隔離外部修改,可以設(shè)置成局部靜態(tài)變量。

+ (instancetype)sharedInstance {
    static Singleton *sharedInstance = nil;
    if (sharedInstance == nil) {
        sharedInstance = [[Singleton alloc] init];
    }
    
    return sharedInstance;
}

單例的核心思想就算實現(xiàn)了。

多線程如何處理?

上述例子雖然實現(xiàn)了單例的核心思想,但依然存在問題。在多線程情況下即多個線程同時訪問sharedInstance工廠方法,并不能保證只創(chuàng)建一個實例對象。

那么,如何保證在多線程的下依舊能夠只創(chuàng)建一個實例對象呢?iOS下我們可以使用NSLock、@synchronized等多種線程同步技術(shù)。

+ (instancetype)sharedInstance {
    static Singleton *sharedInstance = nil;
    @synchronized (self) {
        if (sharedInstance == nil) {
            sharedInstance = [[Singleton alloc] init];
        }
    }

    return sharedInstance;
}

@synchronized雖然保證了在多線程下調(diào)用sharedInstance工廠方法只會創(chuàng)建一個實例對象,但是@synchronized的性能較差。OC內(nèi)部提供了一種更加高效的方式,那就是dispatch_once@synchronized性能相較于dispatch_once要差幾倍,甚至幾十倍。關(guān)于二者的性能對比,請參考這里

+ (instancetype)sharedInstance {
    static Singleton *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[Singleton alloc] init];
    });

    return sharedInstance;
}

Objective-C中實現(xiàn)單例存在的坑

上述實現(xiàn)單例的方式看起來很完美了。雖然我們提供了一個方便的工廠方法返回單例,但是用戶依然能夠調(diào)用alloc方法創(chuàng)建對象。這樣外部使用的時候依舊能夠創(chuàng)建多個實例。解決上述問題有兩種方案:

1. 技術(shù)上實現(xiàn)無論怎么調(diào)用都返回同一個單例對象

To create a singleton as the sole allowable instance of a class in the current process. This code does the following:

  • It declares a static instance of your singleton object and initializes it to nil.
  • In your class factory method for the class (named something like “sharedInstance” or “sharedManager”), it generates an instance of the class but only if the static instance is nil.
  • It overrides the allocWithZone: method to ensure that another instance is not allocated if someone tries to allocate and initialize an instance of your class directly instead of using the class factory method. Instead, it just returns the shared object.
  • It implements the base protocol methods copyWithZone:, release, retain, retainCount, and autorelease to do the appropriate things to ensure singleton status. (The last four of these methods apply to memory-managed code, not to garbage-collected code.)
+ (instancetype)sharedInstance {
    static Singleton *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[super allocWithZone:NULL] init];
    });

    return sharedInstance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [self sharedInstance];
}

- (id)copy {
    return [Singleton sharedInstance];
}

- (id)mutableCopy {
    return [Singleton sharedInstance];
}

如下圖所示,不管使用何種方式創(chuàng)建對象都返回相同的實例對象。


實例變量的地址

2.利用編譯器特性給用戶提示,但不強制約束

利用編譯器特性直接告訴外部newalloc 、copy、mutableCopy方法不能直接調(diào)用,否則編譯不通過。

+ (instancetype)sharedInstance;

+ (instancetype)new OBJC_UNAVAILABLE("use sharedInstance instead.");
+ (instancetype)alloc OBJC_UNAVAILABLE("use sharedInstance instead.");
- (id)copy OBJC_UNAVAILABLE("use sharedInstance instead.");
- (id)mutableCopy OBJC_UNAVAILABLE("use sharedInstance instead.");

若直接調(diào)用alloc等方法創(chuàng)建對象,編譯器則會給出錯誤提示:

編譯器錯誤提示

單例模式潛在的問題

  • 內(nèi)存問題
    單例模式實際上是延長了對象的生命周期,那么就存在內(nèi)存的問題,因為單例對象在程序的整個生命周期里都存在,直到程序退出才會釋放。

參考文獻(xiàn):
Singleton
Creating a Singleton Instance

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 單例模式的意思就是只有一個實例。單例模式確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例。這個類稱...
    Asserts閱讀 443評論 0 1
  • 前言單例模式基本上是最簡單的設(shè)計模式,它使類的一個對象成為整個系統(tǒng)的唯一實例。 基礎(chǔ)款 基本上是最簡單的單例創(chuàng)建形...
    madaoCN閱讀 1,623評論 3 7
  • iOS設(shè)計模式——單例模式http://blog.csdn.net/lovefqing/article/detai...
    LV大樹閱讀 812評論 0 1
  • 什么是單例 ? 單例模式是一種常用的軟件設(shè)計模式。在它的核心結(jié)構(gòu)中只包含一個被稱為單例類的特殊類。通過單例模式可以...
    milk_powder閱讀 2,008評論 0 0
  • 簡介: 單例模式是一種常用的軟件設(shè)計模式。在它的核心結(jié)構(gòu)中只包含一個被稱為單例類的特殊類。通過單例模式可以保證系統(tǒng)...
    RunnerFL閱讀 717評論 0 0

友情鏈接更多精彩內(nèi)容