巨集的應用 (1)

Green Chiu
iOS Nerd 🤓
Published in
5 min readMay 17, 2018

如果想找 Swift 如何使用巨集,這篇文章沒有相關的訊息,請持續追蹤後續的文章,謝謝。

Macro (巨集) 在 Xcode, Objective-C and Swfit 中皆有應用,其中在 Objective-C 的開發以及 Xcode 專案的建置上被大量的使用。Swift 使用的方式上跟 Objective-C 有極大的差異,後續的文章將會繼續討論。

今天再來談談幾個會用到 macro 的情境,我依照我個人的經驗列出下面的項目:

  • Define variables.
  • Adapter
  • NOT Simple but usually use method or function
  • Use Preprocessor Macros to Enable specific information or tool.

上面的項目我會拆分成幾個部分來分享,希望內容能在兩到三篇內結束。

首先我們先來了解在 Objective-C 中,該如何定義巨集跟幾個會使用到的寫法。我列出了四個我們經常使用的方法:

#ifdef
#ifndef
#define
#undef

ifdef/ifndef 是 C Preprocessor 的 condition compilation,用來檢查巨集是否存在,再接著執行對應的陳述式。可以參考下面的 code block:

#ifdef DEBUG
// do something
#endif

這邊要特別注意的事情是,如果條件是沒有成立,#ifdef 裡面的動作將會被 Xcode 直接忽略,無法知道你的實作是否正確;可以先把 macro 加進去或是把先暫時移除 #ifdef 來確保實做正確。

#define MACRO#ifdef MACRO
// Your statement is working
#endif
#undef MACRO#ifdef MACRO
// Your statement can not work
#endif

Define variable

使用 macro 來定義變數,可能是最直接且大多人最喜歡的使用方式了。
我們來來看看該如何來定義 macro 變數:

#define {Macro_Name} {Value} #define Author @"Green" 
#define Age @30
#define Own_a_house NO

上面我定義了一個三個不同的 macro 變數,分別是 AuthorAge 以及 Own_a_house對應的 value 是 Green30 以及 NO;使用起來也非常簡單:

if (!Own_a_house) {
// Do something
}
NSString *name = Author;
NSInteger age = [Age integerValue];

透過上面的例子,我們可以發現定義 macro 變數的時候,不用特別指定類型就可以隨意的將值指定成 Objective-C 所支援的類型,使用的方式也相同。

雖然是很方便的方式,但是我並不推薦這樣使用的使用方式。在變數 in Objective-C 中我有討論到這樣使用會遭遇到的問題與推薦作法,沒看過可以看一下,這邊就不詳述了。

Adapter

在開發的過程中,大家會經常使用 NSLog 來 Trace/Log 需要的資訊來做除錯/驗證,為了不把這些資訊洩漏出去,通常完成的時候再去移除相關的 NSLog。如果在 QA 驗證時候有問題就又必須在把 NSLog 加回去。這一來一往所花費的時間累積起來也是很可觀的。

而 macro 可以讓我們輕鬆地解決這個問題:

#ifdef DEBUG
#define NSLog NSLog
#else
#define NSLog
#endif

上述程式碼,我宣告了一個 macro NSLog ,在有定義 DEBUG 的版本中,他會直接呼叫 NSLog func,不然除了定義 DEBUG 外的版本去使用 NSLog 都會沒有作用,連之前已經加上沒移除的 NSLog func 都會直接被 macro NSLog 覆蓋。

這樣的做法能除了能減少花費在處理 Log 的時間,同時讓 QA 在使用 Debug 版本也能看到這些資訊,降低開發者與 QA 的溝通成本。

除了這個例子之外,我們也很常使用 NSLocalizedString 來支援在地化。NSLocalizedString 需要帶入兩個參數,分別是 “Key” 及 “Comment”,其中的 Comment 可以帶入 nil。用起來會的方式如下:

NSLocalizedString(@"key for string", nil);

如果這個專案對於在地化的需求並沒有使用 comment 的需求,一直反覆的輸入這麼長的名稱且每次都要帶入 nil 也很累。這時候也可以透過 Macro 來幫忙改善這個問題

#define NSLSTR(key) NSLocalizedString(key, nil)

透過新的 macro NSLSTR,就能減少需要輸入很長的名稱以及帶入 nil 花費的時間。

也許你有注意到,在第二個範例裡面我並沒有直接用同樣的變數名稱來定義 NSLocalizedString;主要的原因是因為 NSLocalizedString 本身也是 macro,雖然可以重複的定義相同名稱的 macro,但是這樣很容易造成混淆,因此在對待 macro 的處理方式,會建議你使用新的命名來做一些區分。

以上是關於 macro 變數跟使用 macro 來轉換/橋接不同實作的經驗分享,如果你有疑問或是很棒的想法,歡迎提出來一起討論。

That’s all, enjoy it.

--

--

Green Chiu
iOS Nerd 🤓

Do something to improve myself and try everything I like.