iOS 設(shè)計模式之四(單例模式)

一、概念

1、單例模式的動機

? 實際開發(fā)中,為了節(jié)約系統(tǒng)資源,并且共享一份數(shù)據(jù),有時需要確保系統(tǒng)中某個類只有唯一一個實例,當(dāng)這個唯一實例創(chuàng)建成功之后,我們無法再創(chuàng)建一個同類型的其他對象,所有的操作都只能基于這個唯一實例。為了確保對象的唯一性,我們可以通過單例模式來實現(xiàn),這就是單例模式的動機所在。

2、單例模式的定義

? 單例模式(Singleton Pattern):確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例,這個類稱為單例類,它提供全局訪問的方法。單例模式是一種對象創(chuàng)建型模式。

? 單例模式有三個要點:一是某個類只能有一個實例;二是它必須自行創(chuàng)建這個實例;三是它必須自行向整個系統(tǒng)提供這個實例。

3、餓漢式單例與懶漢式單例

餓漢式單例:當(dāng)類被系統(tǒng)加載時,靜態(tài)變量instance會被初始化,單例類的唯一實例將被創(chuàng)建。

懶漢式單例:在類第一次調(diào)用的時候,instance被初始化,單例類的唯一實例將被創(chuàng)建。

4、結(jié)構(gòu)圖

? 這里只放一個普遍的單例模式結(jié)構(gòu)圖,餓漢式單例與懶漢式單例區(qū)別就是靜態(tài)變量instance初始化的時間不同。

單例模式

二、示例

1、餓漢式單例代碼

? 根據(jù)餓漢式單例的定義,在類被加載的時候就對靜態(tài)instance初始化,Java代碼比較簡單:

Class Singleton {
    private static final Singleton instance = new Singleton(); //保證實例唯一
    private Singleton() { } //私有初始化方法
    public static Singleton getInstance() { //利用工廠模式統(tǒng)一提供對外方法
        return instance; 
    }
}

在iOS開發(fā)中,餓漢式單例代碼略顯奇怪:

// .h文件
@interface Singleton : NSObject
+ (instancetype)sharedInstance;
@end

// .m文件
static Singleton *instance; //聲明靜態(tài)變量
@implementation Singleton
+ (void)load { // 在類被加載的時候會調(diào)用一次load方法,這個時候進(jìn)行初始化
    instance = [[super allocWithZone:NULL] init];
}

+ (instancetype)sharedInstance { // 統(tǒng)一對外方法
    return instance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone { //就算通過alloc創(chuàng)建的也是同一個instance
    return instance;
}
@end
2、懶漢式單例代碼

? 根據(jù)懶漢式單例定義,在類第一次調(diào)用的時候?qū)o態(tài)instance進(jìn)行初始化,Java代碼簡單:

class LazySingleton { 
    private static LazySingleton instance = null; //加載的時候不初始化
    private LazySingleton() { } //私有初始化方法
    public static LazySingleton getInstance() { //第一次調(diào)用初始化,synchronized進(jìn)行線程同步
    if (instance == null) {
        synchronized (LazySingleton.class) {
            instance = new LazySingleton(); 
        }
    }
    return instance; 
   }
}

在iOS開發(fā)中,懶漢式單例代碼如下:

// .h文件
@interface Singleton : NSObject
+ (instancetype)sharedInstance;
@end

// .m文件
@implementation Singleton
+ (instancetype)sharedInstance {
    return [[self alloc] init]; //alloc最終會調(diào)用allocWithZone方法
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static Singleton *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{ //dispatch_once里只會調(diào)用一次,是線程安全的
        instance = [[super allocWithZone:NULL] init];
    });
    return instance;
}
@end

運行代碼:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    Singleton *s1 = [Singleton sharedInstance];
    Singleton *s2 = [[Singleton alloc] init];
    NSLog(@"s1 = %p", s1);
    NSLog(@"s2 = %p", s2);
}

打印結(jié)果:s1與s2打印地址是一樣的,是同一個實例。

s1 = 0x60000380c060
s2 = 0x60000380c060
3、iOS項目中常見用法

? 在iOS實際開發(fā)中,經(jīng)常是使用另外一種方式創(chuàng)建單例模式,嚴(yán)格來說這種做法不嚴(yán)謹(jǐn),但是代碼簡單方便,所以使用還是廣泛。

@interface Singleton : NSObject
+ (instancetype)sharedInstance;
@end

@implementation Singleton
+ (instancetype)sharedInstance {
    static Singleton *instance; //聲明靜態(tài)變量
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{ //第一次調(diào)用的時候初始化一次
        instance = [Singleton new];
    });
    return instance;  //返回靜態(tài)變量
}
@end

這種做法,如果通過alloc創(chuàng)建的實例會不一樣。

運行代碼:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    Singleton *s1 = [Singleton sharedInstance];
    Singleton *s2 = [[Singleton alloc] init];
    NSLog(@"s1 = %p", s1);
    NSLog(@"s2 = %p", s2);
}

打印結(jié)果:s1和s2指針地址不同,是不同的instance。

s1 = 0x600001e58ed0
s2 = 0x600001e58f40

三、總結(jié)

? 單例模式作為一種目標(biāo)明確、結(jié)構(gòu)簡單、理解容易的設(shè)計模式,在軟件開發(fā)中使用頻率相當(dāng)高。

1、優(yōu)點

1、單例模式提供了對唯一實例的受控訪問。因為單例類封裝了它的唯一實例,所以它可以嚴(yán)格控制客戶怎樣以及何時訪問它。

2、由于在系統(tǒng)內(nèi)存中只存在一個對象,因此可以節(jié)約系統(tǒng)資源,對于一些需要頻繁創(chuàng)建和銷毀的對象單例模式無疑可以提高系統(tǒng)的性能。

2、缺點

1、由于單例模式中沒有抽象層,因此單例類的擴展有很大的困難。

2、單例類的職責(zé)過重,在一定程度上違背了“單一職責(zé)原則”。因為單例類既充當(dāng)了工廠角色,提供了工廠方法,同時又充當(dāng)了產(chǎn)品角色,包含一些業(yè)務(wù)方法,將產(chǎn)品的創(chuàng)建和產(chǎn)品的本身的功能融合到一起。

3、現(xiàn)在很多面向?qū)ο笳Z言(如Java、C#)的運行環(huán)境都提供了自動垃圾回收的技術(shù),因此,如果實例化的共享對象長時間不被利用,系統(tǒng)會認(rèn)為它是垃圾,會自動銷毀并回收資源,下次利用時又將重新實例化,這將導(dǎo)致共享的單例對象狀態(tài)的丟失。

3、適用場景

1、系統(tǒng)只需要一個實例對象。

2、客戶調(diào)用類的單個實例只允許使用一個公共訪問點,除了該公共訪問點,不能通過其他途徑訪問該實例。

4、iOS應(yīng)用舉例

? 比如UIApplication就是一個單例類,提供全局的應(yīng)用服務(wù),比如NSFileManager文件管理類。

Demo地址:iOS-Design-Patterns

最后編輯于
?著作權(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)容

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