首先,預先處理命令他不是一個常量!!!!
我們來看一段代碼
#define avatar @"60" if (false) { #define avatar @"80" } NSLog(avatar);
這段代碼會輸出多少,我們將“avatar”定義為了60,然後在一個永遠不會執行的代碼裡面重新定義了“avatar”為80,if語句中的代碼永遠不會執行,但是在編譯時間期,編譯器會編譯這段代碼,而這個時候編譯器就會將avatar這個名字替換為@“80”,所以這段代碼最後的輸出結果就是80。
當然這個時候編譯器是會有一個警告的,但是不知道有多少同學會忽略這個警告。或者你會告訴我你對警告十分敏感,不會放過他的,但是記住你不是一個人在寫代碼,可能在別人的頁面他給你重新定義了你的define,給你挖了一個大坑,還找不著.........
用const來定義一個常量
const修飾符定義的變數是不可變的,比如說你需要定義一個動畫時間的常量,你可以這麼做:
static const NSTimeInterval kAnimateDuration = 0.3;
當你試圖去修改“ kAnimateDuration”的值的時候,編譯器會報錯。更加重要的是用這種方法定義的常量是帶有類型資訊的,而這點則是define不具備的。
也許你已經發現了,如果你像這樣定義:
static const NSString * kUserName = @"StrongX";
你是可以修改userName的值的,(說好的常量呢~~~)
首先我們需要確定的是以下兩種寫法是一樣的:
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指向的記憶體塊地址,而他的輸出是:
輸出
我們已經發現當我們改變記憶體的記憶體的時候他的地址並沒有發生改變,也就是說這是符合“const”修飾符的規定的。
而當我們的修飾符是這樣的時候:
static NSString * const kUserName = @"StrongX";
我們則無法改變userName的值。
所以當我們需要定義一個不可變的常量的時候 ,我們還是需要將“const”修飾符放到“*”指標指向符後邊才對。
一定要同時使用static和const來定義你的變數
上面已經說了const是用來定義一個常量。而static在C語言中(OC中延用)則表明此變數只在改變數的輸出檔案中可用(.m檔案),如果你不加“static”符號,那麼編譯器就會對該變數建立一個“外部符號”,後果是什麼呢?
你可以嘗試在不同編譯檔案中加入以下代碼:
NSString * const kUserName = @"StrongX";
可能儘管檔案之間並沒有相互引用,不存在屬性名稱重複的問題(因為這並不是一個屬性,這是一個外部符號),但是編譯器還是報錯了:
他會告訴你在兩個目標檔案(.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坑慘了!)。
以上就是本文的全部內容,希望本文提到的知識點對大家開發IOS時有所協助,讓大家都能使用正確的規範開發IOS。