天天看點

Objective C--單例模式

今天想和大家一起分享的是單例模式。顧名思義,單例模式的特點就是保證一個類僅有一個執行個體。因為這個模式隻和一個類有關,沒有類與類之間的關系,所有就不給出圖示了。那麼還是先說一下基本的定義。

單例模式(Singleton),保證一個類僅有一個執行個體,并提供一個通路它的全局通路點。

通常我們可以讓一個全局變量使得一個對象被通路,但它不能防止你執行個體化多個對象。一個最好的辦法就是,讓類自身負責儲存它的唯一執行個體。這個類可以保證沒有其他執行個體可以被建立,并且它可以提供一個通路該執行個體的方法。平時,我們常用單例模式的地方通常是多線程。

因為Objective C傳承了Smalltalk語言,是以在Objective C中實作單例模式和C++和C#以及Java都不太一樣。因為要保證類型對象的單一性,是以就要考慮Objective C在執行個體化對象時候的各種方式。因為在Objective C中建立的各個類型都繼承自NSObject類型,是以我們需要考慮NSObject類型裡執行個體化的方法,下面讓我們展開來說。

在Objective C的執行個體化對象的方式主要有三種,分别如下:

  1. obj = [NSObject new];
  2. obj = [[NSObject alloc]init];
  3. obj = [[NSObject allocWithZone]init];

 NSObject類參考文檔裡記錄第三種方法是因為曆史原因遺留下來的,在目前的Objective C中已經不再使用,是以我們就不考慮這種方式了。下面讓我們主要看一下前兩種方式。

第一種方式,用new方法初始化其實是第二種方式的總和,當調用new方法時,其實是先調用了alloc方法進行isa(is a pointer)操作,建立指針,指向記憶體中的資料結構,緊接着調用了init方法對資料進行初始化,NSObject類參考文檔裡也有具體的說明,大家也可以檢視文檔,具體實作方式随後我會用代碼向大家進行展示。

第二種方式看起來就很明确了,先調用alloc建立指針指向記憶體中的資料結構,再調用init方法初始化資料。這裡需要注意的是,init方法隻是起到了初始化資料的作用,其實也可以自定義初始化方法,即完全可以自定義一個普通傳回NSObject類型的方法來代替init方法,即init方法是可以随意被代替的。隻不過NSObject類型中new方法預設會調用init方法而已,init方法可以看作是NSObject類型的預設構造函數。

是以綜上所述,其實隻有alloc方法是每次必須調用的方法,那麼我們隻要控制住alloc方法,對此方法進行覆寫就可以保證類型對象的單一性了。好了,說了這麼多,讓我們看看如何實作吧。

  • Singleton類接口
1 2 3 4 5 6

#import <Foundation/Foundation.h>

@interface

Singleton:

NSObject

+(Singleton*)GetInstance;

-(

void

)SayHello;

@end

  • Singleton類實作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

#import "Singleton.h"

@implementation

Singleton

static

Singleton *myInstance =

nil

;

static

int

num;

+(Singleton*)GetInstance{

@synchronized

([Singleton

class

]){

if

(myInstance ==

nil

){

myInstance = [[

self

alloc]init];

}

}

return

myInstance;

}

+(

id

)alloc{

@synchronized

([Singleton

class

]){

if

(myInstance ==

nil

) {

myInstance = [

super

alloc];

num++;

NSLog

(@

"對象數目:%d"

,num);

}

else

{

NSLog

(@

"不好意思,你在執行個體化第二個對象"

);

}

return

myInstance;

}

return

nil

;

}

-(

id

)init{

self

= [

super

init];

if

(

self

!=

nil

){

NSLog

(@

"初始化資料"

);

}

return

self

;

}

-(

void

)SayHello{

NSLog

(@

"Hello,world!"

);

}

@end

  • Main方法調用
1 2 3 4 5 6 7 8 9 10 11 12 13

#import <Foundation/Foundation.h>

#import "Singleton.h"

int

main (

int

argc,

const

char

*argv[])

{

@autoreleasepool

{

Singleton *singleton = [Singleton GetInstance];

[singleton SayHello];

singleton = [Singleton

new

];

[singleton SayHello];

}

return

0;

}

在Main方法中,當調用new方法進行第二次執行個體化的時候你會發現,Singleton類型的alloc方法第二次被調用了,并列印出“不好意思,你在執行個體化第二個對象”的語句。至此,不管是調用new方法還是調用alloc方法,還是調用自定義的GetInstance方法都隻能生成一個對象執行個體。

有的同學可能不太清楚@synchronized(){...}功能是什麼,簡單的說是線程鎖,起到通路互斥的作用,詳細見這裡。

好啦,至此,一個簡單的單例模式就實作了。其實,在Objective C裡實作單例模式還是有一些其他的争議的,比如說如何實作的更合理之類的,這裡隻是給出了一種方式而已,有興趣的大家可以Google一下。

繼續閱讀