在使用RAC的代码中看到@weakify和@strongify的使用,第一感觉应该是 __weak和__strong的使用,于是就看了一下,关于这两者的定义:
@weakify:
#define weakify(...) \
rac_keywordify \
metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
在@weakify的定义的注释中是这么写的:Creates \c __weak shadow variables for each of the variables provided as arguments, which can later be made strong again with #strongify.
创建一个weak的变量引用作为参数提供给每一个需要调用的地方,之后能够再一次变成strong 通过strongify的方式。
那接下来就看一下weakify 的定义:
metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
其中的(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)这部分是参数,我们之后再来看,先看metamacro_concat 这个的定义:
metamacro_concat:
#define metamacro_concat(A, B) \
metamacro_concat_(A, B)
接下来是metamacro_concat_ 这个函数的定义:
metamacro_concat_:
#define metamacro_concat_(A, B) A ## B
这个函数首先要认清运算符 “##” ,这里是连字符的意思,就是A ## B == AB
那么倒推到上面的的宏定义就变成:
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
(metamacro_foreach_cxt ## metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
接下来就需要先看这个metamacro_argcount:,之后后面需要连接的参数是什么。
metamacro_argcount:返回参数的个数
* Returns the number of arguments (up to twenty) provided to the macro. At least one argument must be provided.
#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_at的定义:
/**
* Returns the Nth variadic argument (starting from zero). At least
* N + 1 variadic arguments must be given. N must be between zero and twenty,
* inclusive.
*/
#define metamacro_at(N, ...) \
metamacro_concat(metamacro_at, N)(__VA_ARGS__)
通过宏的注释可以得到:返回N个可辨的参数,至少需要给出N+1 个可变的参数,而且N必须在0到20之间。
所以上面的:
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_at20( __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)的样子。
然后看函数metamacro_at20 的定义:
#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__)
这时需要看metamacro_head 的定义:
#define metamacro_head(...) \
metamacro_head_(__VA_ARGS__, 0)
根据定义的注释:* Returns the first argument given. At least one argument must be provided.
可以得知,返回第一个参数,而且至少需要一个参数。
进一步去看宏定义metamacro_head_,
#define metamacro_head_(FIRST, ...) FIRST
那么就可以知道此时的metamacro_head返回的是参数列表的第一个参数。
那么之前的宏的定义:
metamacro_at20( __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)返回的是参数列表中参数的个数,就是__VA_ARGS__参数的个数。
也就是metamacro_at20 返回的是N,而N是__VA_ARGS__的个数。
于是最上面的:metamacro_argcount(__VA_ARGS__) 就变成了metamacro_at20( __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1),所以:
(metamacro_foreach_cxt ## metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)=======>>>>
(metamacro_foreach_cxt ## metamacro_at20( __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1))(MACRO, SEP, CONTEXT, __VA_ARGS__)=======>>>>
(metamacro_foreach_cxt ## N)(MACRO, SEP, CONTEXT, __VA_ARGS__)
假如此时传入的是self的话那么此时就会变成:
metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, __VA_ARGS__)这样,也就是weakify(...) 转换后的形式。
那就看一下metamacro_foreach_cxt1 的宏定义:
#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
而我们在定义weakify的时候传递的参数是:
#define weakify(...) \
rac_keywordify \
metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
所以我们的参数是:rac_weakify_,, __weak, __VA_ARGS__
metamacro_foreach_cxt1(rac_weakify_,, __weak, __VA_ARGS__)rac_weakify_(0,__weak ,__VA_ARGS__)
weakly(self)的时候就变成了,如下:
metamacro_foreach_cxt1(rac_weakify_,, __weak,self)rac_weakify_(0,__weak ,self)
那么接下来就需要看 宏定义rac_weakify_的:
rac_weakify_:
#define rac_weakify_(INDEX, CONTEXT, VAR) \
CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);
那么此时的rac_weakify_(0,__weak ,self)就应该写成:
__weak __typeof__(self) self_weak_ = self
weakly(self)弱化后的self 就这样实现了。
@strongify的定义:
先看strongify的定义:
#define strongify(...) \
rac_keywordify \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
metamacro_foreach(rac_strongify_,, __VA_ARGS__) \
_Pragma("clang diagnostic pop")
去除没用的部分就剩下了:
metamacro_foreach(rac_strongify_,, __VA_ARGS__)部分,这部分的定义如下:
#define metamacro_foreach(MACRO, SEP, ...) \
metamacro_foreach_cxt(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__)
到了这里就是和之前的weakify部分一样的了。
就变成了metamacro_foreach_cxt(metamacro_foreach_iter,, rac_strongify_, __VA_ARGS__)
strongly(self)此时就变成了metamacro_foreach_cxt(metamacro_foreach_iter,, rac_strongify_, self)
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
接下来就是:
metamacro_foreach_cxt ## 1(metamacro_foreach_iter,, rac_strongify_, self)
metamacro_foreach_cxt1(metamacro_foreach_iter,, rac_strongify_, self)
接下来:
#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
======>
metamacro_foreach_cxt1(metamacro_foreach_iter,, rac_strongify_, self) === metamacro_foreach_iter(0, rac_strongify_, self)
接下来就是:metamacro_foreach_iter:
#define metamacro_foreach_iter(INDEX, MACRO, ARG) MACRO(INDEX, ARG)
那么此时的metamacro_foreach_iter(0, rac_strongify_, self) 就变成了:
metamacro_foreach_iter(0, rac_strongify_, self) = rac_strongify_(0, self)
再看rac_strongify_ ,那么就是:
#define rac_strongify_(INDEX, VAR) \
__strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_);
那么此时:
rac_strongify_(0, self)
=========>
__strong __typeof__(self) self = self_weak_
那么最后就变成了:
__weak __typeof__(self) self_weak_ = self
__strong __typeof__(self) self = self_weak_
需要注意的是:strong 必须在block中使用:
使用的方式如下:
__weak __typeof__ (self) self_weak_ = (self);
ViewController *VC = [[RootViewController alloc]init];
[VC successBlock:^{
__strong __typeof__(self) self = self_weak_;
}];
从上所述: