前言
在RAC中@weakify和@strongify可以實現(xiàn)_weak和_strong的效果,即在block內(nèi)部管理對self的引用劈猿,在項目中通常以下面這種形式展示出來
@weakify(self); // 定義了一個__weak的self_weak_變量
[RACObserve(self, name) subscribeNext:^(NSString *name) {
@strongify(self); // 局域定義了一個__strong的self指針指向self_weak
self.textLabel.text = name;
}];
看得多了就想知道它內(nèi)部到底是怎么實現(xiàn)的~
內(nèi)部實現(xiàn)
打開Xcode找到Product->PreformAction-Process "當(dāng)前使用@weakify或@strongify的文件",可以看到這兩個宏展開之后的最終效果如下:
@autoreleasepool {} __attribute__((objc_ownership(weak))) __typeof__(self) self_weak_ = (self);;
__attribute__((objc_ownership(strong))) __typeof__(self) self = self_weak_;
@autoreleasepool{}實現(xiàn)了添加@的效果筷黔,)attribute((objc_ownership(weak)))就是weak的實現(xiàn)仗颈,_typeof的作用是取類型,相當(dāng)于創(chuàng)建了歐引用self的self_weak的局部變量请祖。
attribute((objc_ownership(strong)))相當(dāng)于_strong,創(chuàng)建了self_weak的強引用,變量名為self
宏展開
以@weakify為例:
- 第一層
#define weakify(...) \
rac_keywordify \
metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
分析:
rac_keywordify的宏定義是
#define rac_keywordify autoreleasepool {}
,這么做是為了可以添加@~metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
刷晋,有多個參數(shù)慎陵,第一個參數(shù)是CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR)
,第二個參數(shù)沒有,第三個是weak蒙幻,最后__VA_ARGS__
是多參數(shù)的意思,代表self胆筒,缺省號代表一個可以變化的參數(shù)表。使用保留名__VA_ARGS__
把參數(shù)傳遞給宏抒和。當(dāng)宏的調(diào)用展開時彤蔽,實際的參數(shù)就傳遞給metamacro_foreach_cxt
了
- 第二層
分解metamacro_foreach_cxt
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
__VA_ARGS__
是可變參數(shù),獲取在...中傳入的N個參數(shù)
metamacro_argcount
metamacro_argcount
這個宏用來獲得參數(shù)的個數(shù)镊辕,文檔說返回提供給該宏的參數(shù)個數(shù)(超過20個)蚁袭,至少一個必須提供,展開如下:
#define metamacro_argcount(...) \
metamacro_at(20, self, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
metamacro_at展開如下:
#define metamacro_at(20, self) \
metamacro_concat(metamacro_at, N)(__VA_ARGS__)
因為metamacro_concat展開
是 A ## B
的意思卖哎,metamacro_at拼接參數(shù)N后變成如下樣子:
metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19,...)
截斷了前面20個參數(shù)因為...
此時代表1
展開是這個:metamacro_head(1)删性,后面metamacro_head_(FIRST,...)FIRST,因為返回第一個,所以參數(shù)個數(shù)是1
回到metamacro_foreach_cxt
就變成
metamacro_foreach_cxt##metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
metamacro_argcount
既然返回的是參數(shù)個數(shù)那么就可以變成這樣
metamacro_foreach_cxt##N(MACRO, SEP, CONTEXT, __VA_ARGS__)
N是參數(shù)個數(shù)维贺,在這里是1
metamacro_foreach_cxt1
的實現(xiàn)實現(xiàn)是這樣的
#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
最終可以寫成
metamacro_foreach_cxt1(rac_weakify_, , __weak, self) rac_weakify_(0,__weak,self)
@strongify原理也差不多,這里就不多說了
PS:@weakify幸缕、@strongify是不會聯(lián)想的,不會聯(lián)想weakify和strongify发乔,經(jīng)常使用可以把它們加入代碼段
小結(jié)
RAC中對宏的使用出神入化,想弄清楚還是看源碼多多推敲~