Object-C 中的單例模式

最近很多文章都在講如何在 Object-C 中實(shí)現(xiàn)單例,但是它們大都沒(méi)有講全。

首先來(lái)看看 單例(Singleton) 的定義:

In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.

來(lái)自Wikipedia

就是說(shuō),單例模式的目的就是在應(yīng)用程序的生命周期中,限制某個(gè)類的實(shí)例只能有一個(gè)嗜傅。

下面來(lái)看幾個(gè)在 OC 中常用的『?jiǎn)卫环绞健?/p>

方式1

方式1符合那些具有面向?qū)ο缶幊探?jīng)驗(yàn)的程序員一般思維茅诱,因此很自然的會(huì)想到下面的實(shí)現(xiàn)方式:

@interface DownloadManager : NSObject
@end

@implementation DownloadManager
static DownloadManager* _sharedInstance = nil;

+ (DownloadManager*)manager
{
    @synchronized(self.class)
    {
        if (_sharedInstance == nil) {
            _sharedInstance = [[self.class alloc] init];
        }

        return _sharedInstance;
    }
}
@end

注意上面代碼中使用了 @synchronized 來(lái)確保在多線程情況下也可以正常的工作逗物。之后我們會(huì)按照『約定』,凡是在需要獲得 DownloadManager 實(shí)例時(shí)瑟俭,統(tǒng)一使用:

DownloadManager* manager = [DownloadManager manager];

方式2

@interface DownloadManager : NSObject
@end

@implementation DownloadManager

+ (DownloadManager*)manager
{
    static DownloadManager* instance = nil;
    static dispatch_once_t once;

    dispatch_once(&once, ^{
        instance = [[self.class alloc] init];
    });
    return instance;
}
@end

上面的代碼使用了 dispatch_once 來(lái)確保創(chuàng)建實(shí)例的代碼只會(huì)被運(yùn)行一次翎卓。注意這次我們并沒(méi)有使用 @synchronized 這是因?yàn)?dispatch_once 是 thread-safety,這是 Apple Doc 中的相關(guān)描述:

This function is useful for initialization of global data (singletons) in an application. Always call this function before using or testing any variables that are initialized by the block.

If called simultaneously from multiple threads, this function waits synchronously until the block has completed.

The predicate must point to a variable stored in global or static scope. The result of using a predicate with automatic or dynamic storage (including Objective-C instance variables) is undefined.

同樣的摆寄,之后我們也會(huì)按照約定失暴,凡是在需要獲得 DownloadManager 實(shí)例時(shí),統(tǒng)一使用:

DownloadManager* manager = [DownloadManager manager];

注意到上面的文字描述中微饥,多次強(qiáng)調(diào)了按照『約定』逗扒,為什么這么說(shuō)呢?這是因?yàn)榍烽伲词刮覀兌x了 manager 這個(gè)方法矩肩,但是我們并不能確保調(diào)用者不會(huì)這樣使用:

DownloadManager* manager = [[DownloadManager alloc] init];

所以說(shuō),上面的方式1和方式2實(shí)際上嚴(yán)格來(lái)說(shuō)肃续,并不是真正的『?jiǎn)卫J健?/p>

Swift 中的單例

為了有一個(gè)對(duì)比黍檩,知道什么是嚴(yán)格意義的單例模式叉袍,我們可以看看在 Swift 中如何實(shí)現(xiàn)單例模式:

class DownloadManager {
    static let manager = DownloadManager()
    private init() { }
}

注意到使用了 private 來(lái)限制了 init 的訪問(wèn)級(jí)別,我們知道在 Swift 中訪問(wèn)控制的最小顆粒度是到文件級(jí)別刽酱,這并不是問(wèn)題喳逛,因?yàn)橥ǔN覀儠?huì)把類定義在一個(gè)單獨(dú)的文件中。

現(xiàn)在在需要獲取 DownloadManager 的實(shí)例時(shí)棵里,只能通過(guò):

let manager = DownloadManager.manager

如果你試圖這樣(注意訪問(wèn)控制的最小顆粒度是文件):

let manager = DownloadManager()

你會(huì)得到一個(gè)錯(cuò)誤提示:

到底是方式1還是方式2

現(xiàn)在我們知道了在 OC 中如果需要實(shí)現(xiàn)單例模式的話润文,有上面的方式1和方式2兩種方式,那么我們應(yīng)該選擇它們中的哪一個(gè)呢衍慎?答案是方式2转唉。

我們選擇方式2的原因有這么幾個(gè):

  1. 從語(yǔ)義上來(lái)講,方式2更加的清晰明了稳捆,因?yàn)槲覀冎?dispatch_once 的意思就是對(duì)某個(gè)任務(wù)只執(zhí)行一次赠法,這很符合我們單例的需求。
  2. 從性能上來(lái)說(shuō)乔夯,dispatch_once 具有更高的性能砖织。

說(shuō)到性能問(wèn)題,最好還是有 benchmark tests末荐,剛好有人已經(jīng)做了相關(guān)的測(cè)試侧纯,下面就是他測(cè)試的結(jié)果:

Single threaded results
-----------------------
  @synchronized: 3.3829 seconds
  dispatch_once: 0.9891 seconds

Multi threaded results
----------------------
  @synchronized: 33.5171 seconds
  dispatch_once: 1.6648 seconds

如果你需要測(cè)試的源碼的話,可以去作者的基hub甲脏。

從上面的測(cè)試中我們看到 dispatch_once 不管在多線程還是單線程情況下眶熬,都要比 @ synchronized 快很多。

作為最后的結(jié)語(yǔ)块请,讓我們擁抱 Swift 吧??娜氏。

總有陽(yáng)光的人給我點(diǎn)贊??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市墩新,隨后出現(xiàn)的幾起案子贸弥,更是在濱河造成了極大的恐慌,老刑警劉巖海渊,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绵疲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡臣疑,警方通過(guò)查閱死者的電腦和手機(jī)盔憨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)讯沈,“玉大人郁岩,你說(shuō)我怎么就攤上這事。” “怎么了驯用?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)儒老。 經(jīng)常有香客問(wèn)我蝴乔,道長(zhǎng),這世上最難降的妖魔是什么驮樊? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任薇正,我火速辦了婚禮,結(jié)果婚禮上囚衔,老公的妹妹穿的比我還像新娘挖腰。我一直安慰自己,他們只是感情好练湿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布猴仑。 她就那樣靜靜地躺著,像睡著了一般肥哎。 火紅的嫁衣襯著肌膚如雪辽俗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天篡诽,我揣著相機(jī)與錄音崖飘,去河邊找鬼。 笑死杈女,一個(gè)胖子當(dāng)著我的面吹牛朱浴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播达椰,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼翰蠢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了砰碴?” 一聲冷哼從身側(cè)響起躏筏,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎呈枉,沒(méi)想到半個(gè)月后趁尼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡猖辫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年酥泞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啃憎。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡芝囤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情悯姊,我是刑警寧澤羡藐,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站悯许,受9級(jí)特大地震影響仆嗦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜先壕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一瘩扼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧垃僚,春花似錦集绰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)包券。三九已至,卻和暖如春溅固,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背侍郭。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工询吴, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人亮元。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像爆捞,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子煮甥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 往事回憶之ObjC單例Swift是Objective-C的一種自然演變盗温,它用如下的方式實(shí)現(xiàn)單例: 在這個(gè)現(xiàn)成方案中...
    王小賓閱讀 3,171評(píng)論 0 5
  • 在之前的帖子里聊過(guò)狀態(tài)管理有多痛苦,有時(shí)這是不可避免的成肘。一個(gè)狀態(tài)管理的例子大家都很熟悉卖局,那就是單例双霍。使用Swift...
    Tank丶Farmer閱讀 6,373評(píng)論 0 5
  • 在之前的帖子里聊過(guò)狀態(tài)管理有多痛苦批销,有時(shí)這是不可避免的染坯。一個(gè)狀態(tài)管理的例子大家都很熟悉,那就是單例单鹿。使用Swift...
    TomatosX閱讀 1,039評(píng)論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)羞反,斷路器囤萤,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • 在使用swift編程語(yǔ)言進(jìn)行iOS應(yīng)用開發(fā)的時(shí)候,我們常常借助單例來(lái)進(jìn)行狀態(tài)管理富雅,但由于實(shí)現(xiàn)單例的方法很多,問(wèn)題就...
    突然自我閱讀 626評(píng)論 0 0