靜態變量和單例模式
1.靜態變量
靜態變量(Static Variable)在計算機編程領域指在程序執行前系統就為之靜態分配(也即在運行時不再改變分配情況)存儲空間的一類變量。與之相對應的是在運行時只暫時存在的自動變量(即局部變量)與以動態分配方式獲取存儲空間的一些對象,其中自動變量的存儲空間在調用棧上分配與釋放。
不同情況下的作用
除明確標識出變量的生命周期外,將變量聲明為static存儲類還會根據變量屬性不同而有一些特殊的作用:
- 對於靜態全局變量來說,針對某一源文件的以static聲明的文件級變量與函數的作用域只限於文件內(只在文件內可見),也即“內部連接”,因而可以用來限定變量的作用域;
- 對於靜態局部變量來說,在函數內以static聲明的變量雖然與自動局部變量的作用域相同(即作用域都只限於函數內),但存儲空間是以靜態分配而非默認的自動分配方式獲取的,因而存儲空間所在區域不同(一般來說,靜態分配時存儲空間於編譯時在程序數據段分配,一次分配全程有效;而自動分配時存儲空間則是於調用棧上分配,只在調用時分配與釋放),且兩次調用間變量值始終保持一致;
- 對於靜態成員變量來說,在C++中,在類的定義中以static聲明的成員變量屬於類變量,也即在所有類實例中共享,與之相對的就是過程變量。
C示例
在C語言中,帶有靜態變量的程序如下所示:
#include <stdio.h> void func() { static int x = 0; // 在對func的三次調用中,x只進行一次初始化 printf("%d\n", x); // 輸出x的值 x = x + 1; } int main(int argc, char * const argv[]) { func(); // 輸出0 func(); // 輸出1 func(); // 輸出2 return 0; }
2.單例模式
一個單例的類,無論一個應用請求它多少次,都將返回一個相同的實例。一個典型的類允許調用者創建很多實例,而對於單例類來說,一個進程中只能有一個類的實例。一個單例對象提供了全局訪問其類的資源的點。單例常被用在這種單點控制被滿足的情況下,例如一些類需要提供公用的服務或者資源。
你應該從一個單例類的工廠方法中獲得一個全局實例。當第一次被請求的時候這個類應該懶加載一個唯一的實例,並且保證之后沒有其他實例被創建。。一個單例類同時也組織調用者對它實例進行copying,retaining,或者releasing。
在一些Cocoa的框架中用到單例。其中有,NSFileManager,NSWorkspace。在UIKit,UIApplication 和 UIAccelerometer也用到單例。工廠方法以sharedClassType這種名字,方便的返回一個單例對象。例如,在Cocoa框架中,sharedFileManager,sharedColorPanel,sharedWorkspace。
3. IOS中單例的創建
有了上面的知識,我們就比較容易理解單例的創建方式了。首先介紹兩種單例的創建方式。
static AccountManager *DefaultManager = nil; + (AccountManager *)defaultManager { if (!DefaultManager) DefaultManager = [[self allocWithZone:NULL] init]; return DefaultManager; }
在iOS4之后有了另外一種寫法:
+ (AccountManager *)sharedManager { static AccountManager *sharedAccountManagerInstance = nil; static dispatch_once_t predicate; dispatch_once(&predicate, ^{ sharedAccountManagerInstance = [[self alloc] init]; }); return sharedAccountManagerInstance; }
無論上面的方法被調用幾次,靜態變量總初始化一次。關於dispatch_once這個方法,官方是這樣說的:在一個應用的生命周期中執行一個block對象一次且僅一次。predicate參數是一個指向dispatch_once_t結構的指針,用來判斷block有沒有被完成執行。block參數是那個被執行一次的塊。dispatch_once這個函數對於初始化一個應用中的全局數據如單例是很有用的。在使用block塊中初始化的變量的時候,需要首先調用這個函數。如果在多線程情況下同時調用,這個函數同步等待block塊中的內容執行完畢。predicate必須指向一個全局或靜態變量。