iOS開(kāi)發(fā)中你真的會(huì)用#define么!!!?

前言:

不得不說(shuō)在C系語(yǔ)言(C, Objective-C, C++...)中宏(macro)是個(gè)強(qiáng)大的東西, 雖然在基本的語(yǔ)法上面看上去是非常的簡(jiǎn)單, 不過(guò)有時(shí)候正因?yàn)樗膹?qiáng)大和方便, 就會(huì)導(dǎo)致在使用的時(shí)候, 其中會(huì)有很多的注意點(diǎn), 如果不小心被忽略, 那么將會(huì)帶來(lái)完全不想要的結(jié)果. 所以要想靈活的使用它, 那么還是先了解一些比較好. 而且在iOS開(kāi)發(fā)中如果你是使用OC, 那么你可能經(jīng)常會(huì)使用到#define(swift當(dāng)前不支持宏)

首先扔出幾個(gè)宏的定義,調(diào)用這些宏的時(shí)候分別是什么結(jié)果, 看看你能夠在不看后面的情況下, 清楚多少, 當(dāng)然, 如果很清楚, 自然可以忽略后文的八卦了..., 因?yàn)? 你絕對(duì)比我更了解宏...

  1. #define PI 3.14
  • #define log(x) printf("this is test: x = %d", x)

  • #define log(x) printf("this is test: "#x" = %d", x)

  • #define power(x) x*x

  • #define RGBA(r, g, b, a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a]

  • #define print(...) printf(__VA_ARGS__)

  • #define RGB(r, g, b) {\ RGBA(r, g, b, 1.0f);\ }

  • #define weakify( x ) autoreleasepool{} __weak typeof(x) weak##x = x;

  • #define weakify(...) \\ autoreleasepool {} \\ metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)

這里先不解釋上面定義的幾個(gè)宏了, 首先介紹下宏的一些基本東西
  • 程序第一步是在預(yù)編譯之前會(huì)有一些操作, 例如刪除反斜線和換行符的組合, 將每個(gè)注釋用一個(gè)空格替代...,
  • 然后在進(jìn)入預(yù)編譯的時(shí)候, 會(huì)尋找可能存在的預(yù)處理指定(由#開(kāi)頭), 例如C中常用的#include, 或者oc中的#import, #define...很多(條件編譯語(yǔ)句...)
  • 處理#define的時(shí)候,然后預(yù)處理器會(huì)從#開(kāi)始, 一直到執(zhí)行到第一個(gè)換行符(寫代碼的時(shí)候換行的作用), 自然, #define只會(huì)允許定義一行的宏, 不過(guò)正因?yàn)樯厦嫣岬降念A(yù)處理之前會(huì)刪除反斜線和換行符的組合, 所以可以利用反斜線定義多行宏, 在刪除反斜線和換行符的組合后, 邏輯上就成了一行的宏了
  • 宏作用在預(yù)編譯時(shí)期, 其真正的效果就是代碼替換, 而且是直接替換(內(nèi)聯(lián)函數(shù)!!!), 這個(gè)和函數(shù)有著很大的區(qū)別, 并且正因?yàn)槭侵苯犹鎿Q, 在使用的時(shí)候就會(huì)有一些的注意點(diǎn)了, 這個(gè)在后面會(huì)給出例子
  • 宏可以被稱為 類對(duì)象宏, 類函數(shù)宏(開(kāi)篇給的幾個(gè)宏中都已經(jīng)囊括了這兩類)
  • 定義宏的語(yǔ)法很簡(jiǎn)單, 一個(gè)宏定義由三部分組成 , 三分部之間用空格分開(kāi), #define, 宏的名字, 主體 例如第一個(gè)宏#define PI(宏的名字) 3.14(主體), 這里有個(gè)注意點(diǎn)就是, 宏的命名和普通的變量命名規(guī)則相同
  • 宏在預(yù)處理階段只進(jìn)行文本的替換(相當(dāng)于把代碼拷貝粘貼), 不會(huì)進(jìn)行具體的計(jì)算(發(fā)生在編譯時(shí)期)
Snip20160826_1.png
對(duì)于宏的基本的東西就介紹到這里了, 還有一些相關(guān)的東西就在下面解釋一下上面定義的幾個(gè)宏的過(guò)程中提到
  • #define PI 3.14 這是宏的最簡(jiǎn)單的定義了, 可能也是大家應(yīng)用最廣的, 就是使用宏來(lái)定義一些常量(消除魔法數(shù)字)或字符串..., 這一類可以被稱為類對(duì)象宏, 方便代碼閱讀和修改, 使用的時(shí)候直接使用定義的宏的名字, PI, 那么預(yù)處理器就會(huì)將代碼中的PI替換為3.14
float computeAreaWithRadius(float r) {
    return PI * r * r;
}
  • #define log(x) printf("this is test: x = %d", x) 這是宏的第二類定義, 即類函數(shù)宏, 這一類的宏和函數(shù)類似的寫法, ( )中可以寫變量, 用作函數(shù)的參數(shù), 不過(guò), 這個(gè)和函數(shù)的區(qū)別是, 宏的參數(shù)不指定類型, 具體的參數(shù)類型在調(diào)用宏的時(shí)候由傳入的參數(shù)決定(有點(diǎn)其他語(yǔ)言里的泛型的意思), 這個(gè)可以算是和函數(shù)相比的優(yōu)點(diǎn), 下面測(cè)試一些這個(gè)宏的使用, 結(jié)果你猜對(duì)了么?
#define log(x) printf("this is test: x = %d", x)
int main(int argc, const char * argv[]) {
        
    int y = 12;
    log(y); // 輸出為  this is test: x = 12
}
  • #define log(x) printf("this is test: "#x" = %d", x), 這個(gè)定義中和上面的區(qū)別是使用了一個(gè)#運(yùn)算符, #運(yùn)算符被用于利用宏參數(shù)創(chuàng)建字符串, 區(qū)分一下和上面的結(jié)果
#define log(x) printf("this is test: "#x" = %d", x)
int main(int argc, const char * argv[]) {
    int y = 12;
    log(y); 
// 輸出為  this is test: y = 12 (而不是 x = 12, 或者 12 = 12)
// 因?yàn)槭褂?和參數(shù)結(jié)合可以被替換為宏參數(shù)對(duì)應(yīng)的字符串, "#x"表示字符串x, 這里輸入的參數(shù)為y, 則替換為y(不是12)
  log(2+4)// 輸出為 this is test: 2+4 = 6
}
  • #define power(x) x*x 這個(gè)和上面一樣是一個(gè)類函數(shù)宏, 這里我原本的意愿是計(jì)算 x*x即x的平方的值, 不過(guò)這樣的定義宏在有些情況下是會(huì)出問(wèn)題的, 這個(gè)例子就是告訴大家定義類函數(shù)宏的時(shí)候就真的要小心, 不然客人結(jié)果并不是我們預(yù)期的
    #define power(x) x*x
    int x = 2;
    int pow1 = power(x); // pow1 = 2*2 = 4
    int pow2 = power(x+1); //  pow2 = 3 * 3 = 9  ??
    // 顯然對(duì)于pow1 = 4是沒(méi)有問(wèn)題的
    // 不過(guò)對(duì)于pow2 = 9 這個(gè)結(jié)果是有問(wèn)題的, 定義的宏并沒(méi)有達(dá)到我們預(yù)想的效果 結(jié)果為 3*3
    // 因?yàn)? 上面提到過(guò)宏是直接的代碼替換, 這里宏展開(kāi)后就成為了 x+1*x+1 = 2+1*2+1 = 5
    // 這里因?yàn)檫\(yùn)算優(yōu)先級(jí)的原因?qū)е陆Y(jié)果的不一樣, 所以pow應(yīng)該(加上括號(hào))定義為
  #define power(x) (x)*(x)
  • #define RGBA(r, g, b, a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a] 這里是個(gè)簡(jiǎn)單的多參數(shù)的類函數(shù)宏的定義, 這個(gè)宏在使用OC開(kāi)發(fā)的時(shí)候 大家可能都會(huì)喜歡使用
  • #define RGB(r, g, b) {\ RGBA(r, g, b, 1.0f);\ } 這個(gè)宏是一個(gè)"多行宏"定義的示例, 即在除了最后一行的最后加上反斜線(因?yàn)榉葱本€和換行符的組合在預(yù)編譯之前會(huì)被系統(tǒng)刪除), 同時(shí)這個(gè)宏也說(shuō)明了, 宏的定義是可以嵌套的(有些編譯器可能不支持, xcode中是支持的...)
  • #define print(...) printf(__VA_ARGS__) 這個(gè)宏使用了兩個(gè)新的東西...__VA_ARGS__, 這兩個(gè)是用來(lái)定義可變參數(shù)宏的, 可以看到是很簡(jiǎn)單的, 唯一一個(gè)注意點(diǎn)就是, ...要放在參數(shù)的最后, 如果你使用C定義可變參數(shù)的函數(shù)就會(huì)發(fā)現(xiàn)過(guò)程就很復(fù)雜了
#define print(...) printf(__VA_ARGS__)
int main(int argc, const char * argv[]) {
  print("測(cè)試可變參數(shù) ---- %d", 12); // 輸出結(jié)果為: 測(cè)試可變參數(shù) ---- 12
}
  • #define weakify( x ) autoreleasepool{} __weak typeof(x) weak##x = x; 最后一個(gè)宏介紹另外一個(gè)運(yùn)算符 ## 這個(gè)是宏定義中的連接運(yùn)算符, 例如上面的weak##x 就是將weak和參數(shù)x連接在一起, 同時(shí)這一個(gè)宏在iOS開(kāi)發(fā)中是很有用的, 使用block的時(shí)候?yàn)榱讼h(huán)引用 通常使用weakSelf, 那么就可以定義這樣一個(gè)宏, 而不用每次都輸入上面一段重復(fù)的代碼 __weak typeof(self) weakself = self, 那么上面定義的宏和這段代碼一樣會(huì)生成一個(gè)弱引用的新變量, 不過(guò)上面定義的時(shí)候使用了autoreleasepool{}, 這一個(gè)自動(dòng)釋放池本質(zhì)上并沒(méi)有什么用, 只不過(guò)對(duì)調(diào)用weakify會(huì)有影響, 需要使用@weakify(x), ??看上去逼格更高, 不過(guò)在RAC中weakify是另外的方式定義的, (開(kāi)篇給出的第九個(gè)宏定義)這個(gè)就可以自己下去研究一下了.
#define weakify( x ) autoreleasepool{} __weak typeof(x) weak##x = x;
加上 autoreleasepool{}使用宏的時(shí)候就應(yīng)該加上@
像這樣: 
- (void)delay {
    @weakify(self)
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [weakself test];
    });
}
當(dāng)然如果你沒(méi)有加autoreleasepool{}, 使用宏就不用加上@了
#define weakify( x ) __weak typeof(x) weak##x = x;
像這樣: 
- (void)delay {
    weakify(self)
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [weakself test];
    });
}

??這里關(guān)于宏的介紹就先這樣了, 使用宏很多時(shí)候可以讓我們的代碼更容易閱讀和修改, 同時(shí)也可以少寫很多的重復(fù)代碼, 希望你在使用C系語(yǔ)言開(kāi)發(fā)的時(shí)候能夠好好利用這個(gè)方便的東西, 如果你使用OC開(kāi)發(fā)iOS那么宏對(duì)你而言也會(huì)是一大福利, 如果使用swift開(kāi)發(fā)iOS, 那么... 目前swift是不支持宏定義的, 不過(guò)可以使用全局的常量和全局函數(shù)來(lái)替換一部分宏的功能

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末遮糖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子叠赐,更是在濱河造成了極大的恐慌欲账,老刑警劉巖屡江,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異赛不,居然都是意外死亡惩嘉,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門踢故,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)文黎,“玉大人,你說(shuō)我怎么就攤上這事殿较∷是停” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵淋纲,是天一觀的道長(zhǎng)劳闹。 經(jīng)常有香客問(wèn)我,道長(zhǎng)洽瞬,這世上最難降的妖魔是什么本涕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮伙窃,結(jié)果婚禮上菩颖,老公的妹妹穿的比我還像新娘。我一直安慰自己为障,他們只是感情好晦闰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著产场,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舞竿。 梳的紋絲不亂的頭發(fā)上京景,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音骗奖,去河邊找鬼确徙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛执桌,可吹牛的內(nèi)容都是我干的鄙皇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼仰挣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼伴逸!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起膘壶,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤错蝴,失蹤者是張志新(化名)和其女友劉穎洲愤,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體顷锰,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柬赐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了官紫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肛宋。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖束世,靈堂內(nèi)的尸體忽然破棺而出酝陈,到底是詐尸還是另有隱情,我是刑警寧澤良狈,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布后添,位于F島的核電站,受9級(jí)特大地震影響薪丁,放射性物質(zhì)發(fā)生泄漏遇西。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一严嗜、第九天 我趴在偏房一處隱蔽的房頂上張望粱檀。 院中可真熱鬧,春花似錦漫玄、人聲如沸茄蚯。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)渗常。三九已至,卻和暖如春汗盘,著一層夾襖步出監(jiān)牢的瞬間皱碘,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工隐孽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留癌椿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓菱阵,卻偏偏與公主長(zhǎng)得像终蒂,于是被迫代替她去往敵國(guó)和親衍锚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子果善,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容