RAC中宏的解析

一入宏門深似海
從此迷路出不來(lái)

按照慣例先上代碼

    @weakify(self)
    [[self.btn rac_signalForControlEvents:(UIControlEventTouchUpInside)] subscribeNext:^(__kindof UIControl * _Nullable x) {
        @strongify(self)
        self.label.text = @"hello";
    }];

這是RAC中最常用的宏的使用几于。大家都知道需要成對(duì)使用话侧,可傳多個(gè)參數(shù)佛析,為什么呢益老?點(diǎn)開源宏(不是袁弘)進(jìn)行分析。

#define weakify(...) \
    rac_keywordify \
    metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)

其中...代表可變參數(shù)寸莫,即可傳入多個(gè)值捺萌,對(duì)應(yīng)于上面的__VA_ARGS__。比如@weakify(self, _a, _b)編譯時(shí)__VA_ARGS__就會(huì)替換為self, _a, _b”炀ィ現(xiàn)在分成三個(gè)部分來(lái)解析上面的宏桃纯。

1.rac_keywordify

#if DEBUG
#define rac_keywordify autoreleasepool {}
#else
#define rac_keywordify try {} @catch (...) {}
#endif

這里比較簡(jiǎn)單披坏,如果是DEBUG模式态坦,就開啟自動(dòng)釋放池,如果是release模式刮萌,就使用@try/@catch驮配。作者在注釋中說(shuō)明了,這兩種方式都是完美的着茸,并且沒有其他方式壮锻,之所以在DEBUG模式下使用自動(dòng)釋放池,是因?yàn)?code>@try/@catch會(huì)影響XCode的警告功能涮阔,導(dǎo)致返回值的檢查出問題猜绣。比如下面的例子,在release模式下敬特,沒有返回值掰邢,也不會(huì)出現(xiàn)編譯錯(cuò)誤。

@weakify(self);
self.block = ^BOOL {
  @strongify(self);
  NSLog(@"123");
};

所以伟阔,按@weakify(self, _a, _b)舉例子辣之,編譯后的結(jié)果為@autoreleasepool {} metamacro_foreach_cxt(rac_weakify_,, __weak, self, _a, _b)

2.metamacro_foreach_cxt皱炉。

#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
        metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)

#define metamacro_concat(A, B) \
        metamacro_concat_(A, B)

#define metamacro_concat_(A, B) A ## B

#define metamacro_argcount(...) \
        metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

#define metamacro_at(N, ...) \
        metamacro_concat(metamacro_at, N)(__VA_ARGS__)

#define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) metamacro_head(__VA_ARGS__)

#define metamacro_head(...) \
        metamacro_head_(__VA_ARGS__, 0)

#define metamacro_head_(FIRST, ...) FIRST

metamacro_foreach_cxt展開之后又出現(xiàn)兩個(gè)宏metamacro_concatmetamacro_argcount』彻溃現(xiàn)在分別分析。

  • metamacro_concat
    A ## B的意思是連接A和B合搅。比如metamacro_concat(n, 1)編譯后為n1多搀。
  • metamacro_argcount
    metamacro_argcount的作用是返回傳入的可變參數(shù)的個(gè)數(shù)。
    展開為:
    ->metamacro_at(20, self, _a, _b, 20, 19, 18, 17, ···, 6, 5, 4, 3, 2, 1)灾部。
    由于20, self, _a, _b, 20, 19, 18, 17, ···, 6, 5, 4, 3, 2, 1_0, _1, _2, _3, _4, _5, _6, ···, _17, _18, _19, ...一一對(duì)應(yīng)康铭,而_0, _1, _2, _3, _4, _5, _6, ···, _17, _18, _19為20個(gè)固定參數(shù),所以20, self, _a, _b, 20, 19, 18, 17, ···, 6, 5, 4這20個(gè)參數(shù)被固定參數(shù)所取代赌髓,所以只剩下3从藤,2催跪,1對(duì)應(yīng)于...
    ->metamacro_concat(metamacro_at, 20)(self, _a, _b, 20, 19, 18, 17, ···, 6, 5, 4, 3, 2, 1)
    ->metamacro_at20(self, _a, _b, 20, 19, 18, 17,···, 6, 5, 4, ...) metamacro_head(3, 2, 1)
    ->metamacro_at20(self, _a, _b, 20, 19, 18, 17,···, 6, 5, 4, ...) metamacro_head(3, 2, 1)
    ->metamacro_head_(3, 2, 1, 0)
    ->3
    所以如果按@weakify(self)為例呛哟,metamacro_argcount(self)返回的結(jié)果為1叠荠。
    metamacro_foreach_cxt(rac_weakify_,, __weak, self, _a, _b)就可簡(jiǎn)化為
    ->metamacro_concat(metamacro_foreach_cxt, 3)(MACRO, SEP, CONTEXT, __VA_ARGS__)
    ->metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, __VA_ARGS__)
    ->metamacro_foreach_cxt3(rac_weakify_,, __weak, self, _a, _b)
#define metamacro_foreach_cxt0(MACRO, SEP, CONTEXT)
#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)

#define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
    metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \
    SEP \
    MACRO(1, CONTEXT, _1)

#define metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \
    metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
    SEP \
    MACRO(2, CONTEXT, _2)

由于SEP這個(gè)參數(shù)傳的是空,所以該參數(shù)可忽略不計(jì)扫责。根據(jù)上面的宏定義
->metamacro_for_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2)
->metamacro_for_cxt2(MACRO, SEP, CONTEXT, _0, _1) MACRO(2, CONTEXT, _2)
->metamacro_for_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(1, CONTEXT, _1) MACRO(2, CONTEXT, _2)
->MACRO(0, CONTEXT, _0) MACRO(1, CONTEXT) MACRO(2, CONTEXT)
->rac_weakify_(0, __weak, self) rac_weakify_(1, __weak, _a) rac_weakify_(2, __weak, _b)

3.rac_weakify_榛鼎。

#define rac_weakify_(INDEX, CONTEXT, VAR) \
    CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);

所以繼續(xù)轉(zhuǎn)化
->CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR)
->__weak __typeof__(self) metamacro_concat(self, _weak_) = (self)
->__weak __typeof__(self) self_weak_ = (self)
所以得到最終結(jié)果:
->rac_weakify_(0, __weak, self) rac_weakify_(1, __weak, _a) rac_weakify_(2, __weak, _b)
->__weak __typeof__(self) self_weak_ = (self) __weak __typeof__(_a) _a_weak_ = (_a) __weak __typeof__(_b) _b_weak_ = (_b)

使用XCode驗(yàn)證結(jié)果如下:

       @autoreleasepool {} __attribute__((objc_ownership(weak))) __typeof__(self) self_weak_ = (self); __attribute__((objc_ownership(weak))) __typeof__(_a) _a_weak_ = (_a); __attribute__((objc_ownership(weak))) __typeof__(_b) _b_weak_ = (_b);
    [[self.btn rac_signalForControlEvents:(UIControlEventTouchUpInside)] subscribeNext:^(__kindof UIControl * _Nullable x) {
        @autoreleasepool {}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"
 __attribute__((objc_ownership(strong))) __typeof__(self) self = self_weak_; __attribute__((objc_ownership(strong))) __typeof__(_a) _a = _a_weak_; __attribute__((objc_ownership(strong))) __typeof__(_b) _b = _b_weak_;
#pragma clang diagnostic pop
 self.label.text = @"hello";
        _a = @"a";
        _b = @"b";
    }];

__weak經(jīng)過(guò)LLVM會(huì)自動(dòng)轉(zhuǎn)化為__attribute__((objc_ownership(weak)))

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鳖孤,一起剝皮案震驚了整個(gè)濱河市者娱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌苏揣,老刑警劉巖黄鳍,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異平匈,居然都是意外死亡框沟,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門增炭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)忍燥,“玉大人,你說(shuō)我怎么就攤上這事隙姿∶仿ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵输玷,是天一觀的道長(zhǎng)队丝。 經(jīng)常有香客問我,道長(zhǎng)欲鹏,這世上最難降的妖魔是什么机久? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮赔嚎,結(jié)果婚禮上吞加,老公的妹妹穿的比我還像新娘。我一直安慰自己尽狠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布叶圃。 她就那樣靜靜地躺著袄膏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪掺冠。 梳的紋絲不亂的頭發(fā)上沉馆,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天码党,我揣著相機(jī)與錄音,去河邊找鬼斥黑。 笑死揖盘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的锌奴。 我是一名探鬼主播兽狭,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鹿蜀!你這毒婦竟也來(lái)了箕慧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤茴恰,失蹤者是張志新(化名)和其女友劉穎颠焦,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體往枣,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伐庭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了分冈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片圾另。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖丈秩,靈堂內(nèi)的尸體忽然破棺而出盯捌,到底是詐尸還是另有隱情,我是刑警寧澤蘑秽,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布饺著,位于F島的核電站,受9級(jí)特大地震影響肠牲,放射性物質(zhì)發(fā)生泄漏幼衰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一缀雳、第九天 我趴在偏房一處隱蔽的房頂上張望渡嚣。 院中可真熱鬧,春花似錦肥印、人聲如沸识椰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)腹鹉。三九已至,卻和暖如春敷硅,著一層夾襖步出監(jiān)牢的瞬間功咒,已是汗流浹背愉阎。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留力奋,地道東北人榜旦。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像景殷,于是被迫代替她去往敵國(guó)和親溅呢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

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