RAC的@weakify和@strongify

在使用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_;

}];

从上所述:

@weakify和@strongify 其实就是__weak 和 __strong 为了方式block中的循环引用而需要对本身对象的一个弱引用和强饮用。

@weakify === __weak

@strongify === __strong


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容