iOS開發之單例

單例介紹

1.什麼是單例

單例模式是一種常用的軟件設計模式。在它的核心結構中包含一個被稱爲單例類的特殊類。通過單例模式可以保證系統中一個類只有一個實例而且該實例易於外界訪問,從而方便對實例個數的控制並節約系統資源。如果系統在系統中某個類的對象只能存在一個,單例模式是最好的解決方案。

2.單例用處

應用場景:
確保程序運行期某個類,只有一份實例,用於進行資源共享控制。
優勢:
使用簡單,延時求值,易於跨模塊
iOS的系統中用到的一些單例

[UIApplication sharedApplication];
[NSUserDefaults standardUserDefaults];
[NSURLCache sharedURLCache];

iOS單例的創建

1.單線程單例

單例類需要保證只有一個實例,因此在第一次訪問這個實例的時候才創建,之後訪問直接取已經創建好的實例

+(instancetype)shareInstance
{
    static Singleton *singleteon;
    if (!singleteon ) {
    singleteon = [[Singleton alloc] init];
    }
    return singleteon;
}

單線程單例存在一些弊端,在多線程的情況下,會產生線程不安全的情況。嚴格意義上來說,我們還需要把alloc方法變爲私有方法才行,嚴格的單例是不允許再創建其他實例的,而alloc方法可以在外部任意生成實例。但是考慮到alloc屬於NSObject,iOS中無法將alloc變成私有方法,最多隻能覆蓋alloc讓其返回空。不過個人不建議這麼做,一般情況下對alloc不做特殊處理。系統的單例也未對alloc做任何處理

2.@synchronized單例

上面單線程單例,在多線程情況下,可能會出現一些問題。如果兩個線程同時調用shareInstanc,可能會創建出2個singleton出來。所以在對多線程情況下,我們需要使用@synchronize來加鎖

+(instancetype)shareInstance
{
    static Singleton *singleton;
    @synchronized (self) {
    if (!singleton) {
        singleton = [[Singleton alloc] init];
    }
    }
    return singleton;
}

加鎖以後,當多個線程同時調用shareInstance時,由於@synchronized已經加鎖,只能有一個線程創建singleton實例。這樣就解決了多線程調用單例的問題。

3.dispatch_once單例

使用@synchronized雖然一定程度上解決了多線程的問題,但並不完美。因爲只有在singleton未創建時,加鎖纔是必要的。如果singleton已經創建,這個時候還加鎖的話,會影響性能。
在iOS中,GCD爲我們提供方便又高效的方法—dispatch_once

+(instancetype)shareInstance
{
    static Singleton *singleton;
    static dispatch_once_t onceToken;  //1.onceToken = 0;

    dispatch_once(&onceToken,^{
    NSLog(@"%ld",onceToken);       //2.onceToken = 140734537148864
    singleton = [[Singleton alloc] init];
    });

    NSLog(@"%ld",onceToken);   //3.onceToken = -1
    return singleton;
}

dispatch_once爲什麼能做到既解決同步多線程問題

dispatch_once的原理:
dispatch_once主要是根據onceToken的值來決定怎麼去執行代碼。
1.當onceToken = 0時,線程執行dispatch_onceblock中代碼
2.當onceToken = -1時,線程跳過dispatch_onceblock中代碼不執行
3.當onceToken爲其他值時,線程被阻塞,等待onceToken值改變
當線程調用shareInstance,此時onceToken = 0,調用block中的代碼,此時onceToken的值變爲140734537148864。當其他線程再調用shareInstance方法時,onceToken的值已經是140734537148864了,線程阻塞。當block線程執行完block之後,onceToken變爲-1.其他線程不再阻塞,跳過block。下次再調用shareInstance時,block已經爲-1.直接跳過block
dispatch_once設計挺巧妙的。

以後會把博客放在github個人博客上,查看更多博客請點擊github博客地址

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