前言
使用RAC的时候我们常会看到这两个宏@weakify(self)
、@strongify(self)
,用来防止使用block时出现引用闭环。 今天看YYKit的时候,看到里面也写了类似的宏,还是来谈谈这两个宏是怎么实现的吧。
正文
## 宏定义代码 由于YYKit中的weakify、strongify相对比较简单,所以只剖析RAC(2.5)中的weakify、strongify。
1 2 3 4 5 6 7 8 9 10 |
#define weakify(...) rac_keywordify metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__) #define strongify(...) rac_keywordify _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored "-Wshadow"") metamacro_foreach(rac_strongify_,, __VA_ARGS__) _Pragma("clang diagnostic pop") |
一点一点剥开。
weakify
1 2 3 |
#define weakify(...) rac_keywordify metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__) |
rac_keywordify
1 2 3 4 5 |
#if DEBUG #define rac_keywordify autoreleasepool {} #else #define rac_keywordify try {} <a href="http://www.jobbole.com/members/wx895846013">@catch</a> (...) {} #endif |
这段宏定义中的代码开头都少了个@,使得weakify、strongify前面必须加上@,当然也只有这作用。 然后这里为什么要判断DEBUG呢?我也不知道,我觉得这里没必要这样判断。
metamacro_foreach_cxt(rac_weakify_,, weak, __VA_ARGS)
1 2 |
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__) |
先看看最外面的宏定义metamacro_concat
:
1 2 3 4 |
#define metamacro_concat(A, B) metamacro_concat_(A, B) #define metamacro_concat_(A, B) A ## B |
这里有点弄不懂再套一层宏定义的意图,##
的作用是连接两个运算符。
1.然后这个宏的实现变成了这样
1 2 |
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) metamacro_foreach_cxt##metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__) |
MACRO、SEP、CONTEXT
这三个参数先不管 __VA_ARGS__
是可变参数,获取在...
中传入的N个参数。
2.metamacro_argcount(__VA_ARGS__)
1 2 |
#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) |
metamacro_argcount这个宏的作用是获得参数的个数。 为什么能获得参数的个数呢? 我们看看是怎么实现的
1 2 |
#define metamacro_at(N, ...) metamacro_concat(metamacro_at, N)(__VA_ARGS__) |
拼接metamacro_at##N(传入的第一个值,这里是20)(VA_ARGS) 也就是: