多用型別常量替代#define預處理指令

scar1900發表於2019-09-02

Objective-C或者C語言中在定義常量時,有一個大家都比較習慣的方式,就是用預處理的巨集定義常量,比如

#define kAnimationTime  3
複製程式碼

這麼寫有個明顯的問題就是缺乏型別資訊,在標頭檔案引入時,由於是預編譯的指令,常量名稱也可能出現衝突。此時可以使用型別常量來解決這個問題。

static const NSTimeInterval kAnimationTime = 3;
複製程式碼

在實現檔案內部,可以用這種方式代替#define指令。

  • const表示kAnimationTime是一個常量,不可修改。
  • static表示僅在實現檔案內部可見,因為oc以一個.m檔案為編譯單元,static標記的常量僅在當前編譯單元生效,如果不加static關鍵字,編譯器會為kAnimationTime建立一個外部符號,此時,如果其他類有常量名重複,編譯器將會報錯。
  • NSTimeInterval就是當前常量的型別。

所以,外部需要引用常量時,並不需要static關鍵字,?如下:

///標頭檔案中
extern NSString *const KKLLoginNotification;

///實現檔案中
NSString *const KKLLoginNotification = @"KKLLoginNotification"
複製程式碼
  • 實現檔案中宣告KKLLoginNotification常量,並且建立了外部符號
  • extern表示將KKLLoginNotification寫入全域性符號表,這樣編譯器不需要知道KKLLoginNotification的具體定義,只要知道全域性符號表中有KKLLoginNotification,就會允許程式碼使用KKLLoginNotification。

事實上,這也是UIKit等iOS SDK中定義通知所常用的方式。

最後補充一下常量的命名原則:

  • static標記的常量只在當前編譯目標中有效,所以不存在衝突風險,可以新增k為字首標記,如kAnimationTime
  • 寫入外部符號表的常量和其他常量存在名字衝突的風險,全域性都要使用的,建議新增全域性統一的字首,個別類使用的,並和當前類相關的常量,建議在統一字首後在新增對應的類名,比如EOCLoginManagerDidLoginNotification

相關文章