在C語言中偿渡,程序內(nèi)變量或函數(shù)的作用域和壽命是由其存儲類決定的。每個變量都有其生命周期吉拳,或存儲其值的上下文适揉。函數(shù)和變量一樣煤惩,存在于一個特定的范圍或可見域里魄揉,這決定了哪一部分程序知道切能夠訪問它們拭宁。
C里有四種存儲類:
- auto
- register
- static
- extern
auto
auto是默認存儲類,因此通常不需要顯示地使用杰标。當程序運行到相應代碼塊時,auto類型的變量能自動分配內(nèi)存媒区,并且在該程序塊運行完成時釋放掸犬。訪問auto變量僅限于在聲明它們的block,以及任何嵌套的block內(nèi)噪服。
register
絕大多數(shù)Objective-C程序員可能也不熟悉register胜茧,因為它沒有被廣泛的使用在NS世界里。
register行為就像auto雹顺,但不同的是它們不是被分配到堆棧中廊遍,它們被存儲在一個寄存器里。
寄存器能比內(nèi)存提供更快的訪問速度喉前,但由于內(nèi)存管理的復雜性,把變量放在寄存器中并不能保證程序變得更快裕便。事實上见咒,很可能由于在寄存器上占用了不必要的空間而最終被放緩執(zhí)行。使用寄存器實際上只是一個給編譯器存儲變量的建議下翎,實現(xiàn)時可以選擇是否遵從這一點。
建議是最好不要使用register胆萧,因為比起其他任何明顯的方式上加快應用程序郑口,它更容易引起讓人更加頭疼的結(jié)果。
static
作為關(guān)鍵字犬性,static有多重不同的用途。當涉及到存儲類時套利,static意味著以下兩件事情之一:
- 方法或函數(shù)內(nèi)部的一個static變量保留其調(diào)用之間的值鹤耍。
- 全局聲明的一個static變量或方法可以被任何函數(shù)或方法調(diào)用,只要這些方法出現(xiàn)在跟static變量或方法同一個文件中喊衫。
靜態(tài)單例(Static Singletons)
Objective-C 中一個常見的模式是靜態(tài)單例杆怕,在這個case里,一個靜態(tài)聲明的變量被初始化陵珍,并在任何一個函數(shù)或類方法中被返回。 dispatch once
用于保證變量初始化在一個線程安全的方式下只發(fā)生一次:
+ (instancetype)sharedInstance {
static id _sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[self alloc] init];
});
return _sharedInstance;
}
單例模式對于創(chuàng)建整個應用程序共享的對象是很有用的瑟幕,諸如HTTP客戶端或一個通知管理留潦,或創(chuàng)建過程很昂貴的對象,諸如格式化殖卑。
extern
static使得一個特定的文件中的函數(shù)和變量全局可見,extern則使它們對所有文件可見懦鼠。
一般來說屹堰,全局變量并不是一個好主意。由于沒有如何以及何時改變值得限制扯键,常常會導致一些無法調(diào)試的bug。在Objective-C荣刑,對extern有兩個常見和實際的用途。
全局字符串常量
任何時候董习,如果你的應用程序要在一個公共頭文件申明一個非自然語言的字符串常量爱只,都應該將其聲明為外部字符串常量。尤其是在聲明諸如userInfo字典窝趣,NSNotification名稱和NSError域的時候训柴。
該模式是在公共頭文件里申明一個extern的NSString * const
,并在實現(xiàn)文件里定義該NSString * const
:
AppDelegate.h
extern NSString * const kAppErrorDomain;
AppDelegate.m
NSString * const kAppErrorDomain = @"com.example.yourapp.error";
字符串的值并沒有特別的需要注意的事情幻馁,只要它是唯一的。使用字符串常量建立了嚴格的約束预麸,用該常量來代替字符串本身儒将。
公共方法
一些 API 可能會想要公開曝光一些輔助方法。出于僅提供輔助而與具體狀態(tài)無關(guān)的考慮钩蚊,用方法來封裝這些行為是一個很好的方式,而且如果特別有用鸣驱,還可能值得使其全局可用蝠咆。該模式例子如下:
TransactionStateMachine.h
typedef NS_ENUM(NSUInteger, TransactionState) {
TransactionOpened,
TransactionPending,
TransactionClosed,
};
extern NSString * NSStringFromTransactionState(TransactionState state);
TransactionStateMachine.m
NSString * NSStringFromTransactionState(TransactionState state) {
switch (state) {
case TransactionOpened:
return @"Opened";
case TransactionPending:
return @"Pending";
case TransactionClosed:
return @"Closed";
default:
return nil;
}
}