iOS 不要用宏來定義你的常量

首先,預處理命令他不是一個常量!!!!

咱們來看一段代碼動畫

#define avatar @"60"
if (false) {
#define avatar @"80"
}
NSLog(avatar);

這段代碼會輸出多少,咱們將「avatar」定義爲了60,而後在一個永遠不會執行的代碼裏面從新定義了「avatar」爲80,if語句中的代碼 永遠不會執行,可是在編譯時期,編譯器會編譯這段代碼,而這個時候編譯器就會將avatar這個名字替換爲@「80」,因此這段代碼最後的輸出結果就是 80。
固然這個時候編譯器是會有一個警告的,可是不知道有多少同窗會忽略這個警告。或者你會告訴我你對警告十分敏感,不會放過他的,可是記住你不是一我的在寫代碼,可能在別人的頁面他給你從新定義了你的define,給你挖了一個大坑,還找不着………spa

用const來定義一個常量

const修飾符定義的變量是不可變的,好比說你須要定義一個動畫時間的常量,你能夠這麼作:指針

static const NSTimeInterval kAnimateDuration = 0.3;

當你試圖去修改「 kAnimateDuration」的值的時候,編譯器會報錯。更加劇要的是用這種方法定義的常量是帶有類型信息的,而這點則是define不具有的。code

也許你已經發現了,若是你像這樣定義:內存

static const NSString * kUserName = @"StrongX";

你是能夠修改userName的值的,(說好的常量呢~~~)編譯器

首先咱們須要肯定的是如下兩種寫法是同樣的:io

static NSString const * kUserName = @"StrongX";
static const NSString * kUserName = @"StrongX";

也就是說const放在類型前仍是類型後是同樣的效果。而後不一樣效果的是下面這種寫法:編譯

static NSString * const kUserName = @"StrongX";

const 修飾的是他右邊的部分,也就是說:效率

static NSString const * kUserName = static NSString const (* kUserName )

static NSString * const kUserName = static NSString * const (kUserName)

當const修飾的是(userName)的時候,不可變的是userName;星號在C語言中表示
指針指向符,也就是說這個時候
userName指向的內存塊地址不可變,而內存保存的內容是可變的,咱們來作個嘗試:變量

NSLog(@"內存地址: %x",& kUserName);
kUserName = @"superXLX";
NSLog(@"內存地址: %x",& kUserName);

以上NSLog會打印*userName指向的內存塊地址,而他的輸出是:
DF448813-C948-4A8B-A545-7BE2A86EBD08

咱們已經發現當咱們改變內存的內存的時候他的地址並無發生改變,也就是說這是符合「const」修飾符的規定的。
而當咱們的修飾符是這樣的時候:

static NSString * const kUserName = @"StrongX";

咱們則沒法改變userName的值。

因此當咱們須要定義一個不可變的常量的時候 ,咱們仍是須要將「const」修飾符放到「*」指針指向符後邊纔對。

  • ### 必定要同時使用static和const來定義你的變量
    上面已經說了const是用來定義一個常量。而static在C語言中(OC中延用)則代表此變量只在改變量的輸出文件中可用(.m文件),若是你不加「static」符號,那麼編譯器就會對該變量建立一個「外部符號」,後果是什麼呢?
    你能夠嘗試在不一樣編譯文件中加入如下代碼:
NSString * const kUserName = @"StrongX";

可能儘管文件之間並無相互引用,不存在屬性名重複的問題(由於這並非一個屬性,這是一個外部符號),可是編譯器仍是報錯了:

C7F125B8-CADA-435A-8A02-2CB9011F8D9F
他會告訴你在兩個目標文件(.0文件是.m文件編譯後的輸出文件)有一個重複的符號。(OC中沒有相似C++中的名字空間的概念)
因此當你在你本身的.m文件中須要聲明一個只有你本身可見的局部變量(k開頭)的變量的時候必定要同時使用「static」和「const」兩個符號。

定義工程中的全局變量

在咱們的工程中必定會定義不少全局常量,不少人的作法是會建立一個「 constant.h」文件,在這個文件中用#define聲明許多常量,而後將這個頭文件引入「pch」文件中,不能說這麼作不對,可是如同上面說的那 樣define可能被修改,固然在命名規範的狀況下這種狀況不多出現,而且這樣作的效率很高。
然而蘋果更推薦另一種作法:」extern」,這樣作的優點是保持常量絕對不會被修改,而且必定初始化還帶有類型信息。
咱們在」constants.h」文件中,聲明常量:

extern NSString *const XUserName;

而後在「constants.m」中定義他:

NSString *const XUserName = @"StrongX";

用「extern」定義的常量必須也只能初始化一次,不知足必須以及只能一次的條件那麼編譯器就會提醒你。在定義全局變量的時候須要要注意你的命名,你可使用規定好的前綴來命名。

「define」和「extern」各有各的優點,不過我我的仍是比較推薦使用「extern」.(由於以前在一個工程中被define坑慘了——!)。

相關文章
相關標籤/搜索