• 剖析@weakify 和 @strongify


    前言

    使用RAC的时候我们常会看到这两个宏@weakify(self)、@strongify(self),用来防止使用block时出现引用闭环。 今天看YYKit的时候,看到里面也写了类似的宏,还是来谈谈这两个宏是怎么实现的吧。

    正文

    ## 宏定义代码 由于YYKit中的weakify、strongify相对比较简单,所以只剖析RAC(2.5)中的weakify、strongify。

    #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

    #define weakify(...)

        rac_keywordify

        metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)

    rac_keywordify

     

    #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)

    #define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...)

            metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)

    先看看最外面的宏定义metamacro_concat:

    #define metamacro_concat(A, B)

            metamacro_concat_(A, B)

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

    这里有点弄不懂再套一层宏定义的意图,##的作用是连接两个运算符。

    1.然后这个宏的实现变成了这样

    #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__)

    #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这个宏的作用是获得参数的个数。 为什么能获得参数的个数呢? 我们看看是怎么实现的

    #define metamacro_at(N, ...)

            metamacro_concat(metamacro_at, N)(__VA_ARGS__)

    拼接metamacro_at##N(传入的第一个值,这里是20)(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_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__)

    截取前20个数,剩下的传入metamacro_head

    #define metamacro_head(...)

            metamacro_head_(__VA_ARGS__, 0)

    #define metamacro_head_(FIRST, ...) FIRST

    metamacro_head的作用返回第一个参数。 打个比方:@weakify(self),

    metamacro_at20(self,20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

     

    截取前20个参数,那么就应该是metamacro_head_(1),那么返回的就是1。 多个参数同理。

    3.回到metamacro_foreach_cxt

     

    metamacro_foreach_cxt##metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)

    metamacro_argcount既然返回的是参数个数那么就可以变成这样:

    metamacro_foreach_cxt##N(MACRO, SEP, CONTEXT, __VA_ARGS__)

     

    N是参数个数 还是以@weakify(self)打比方:

    metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, __VA_ARGS__)

    metamacro_foreach_cxt1的实现是这样的

    #define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)

    4.到了这里我们就要回到之前传入的三个参数了

    metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)

    代入这些参数就应该是

    metamacro_foreach_cxt1(rac_weakify_, , __weak, self) rac_weakify_(0,__weak,self)

    先不管rac_weakify_如何实现,我们再来看看N=20的时候是怎么实现的。

    #define metamacro_foreach_cxt20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19)

        metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18)

        SEP

        MACRO(19, CONTEXT, _19)

    这里就有点类似递归了,先rac_weakify_(0,__weak,_19), 然后把前19个数传入metamacro_foreach_cxt19,metamacro_foreach_cxt19会rac_weakify_(0,__weak,_18),然后把前18个数传入metamacro_foreach_cxt18…直到metamacro_foreach_cxt1。 而且它是存在保护机制的,要是N=0

    #define metamacro_foreach_cxt0(MACRO, SEP, CONTEXT)

    就不做任何操作。 然后我们再来看rac_weakify_实现了什么。

    rac_weakify_的实现

    #define rac_weakify_(INDEX, CONTEXT, VAR)

        CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);

    INDEX只是第几个的标记,在这里没实际作用。 拿@weakify(self)打比方: rac_weakify_(0,__weak,self) 就会变成这样:

    __weak __typeof__ (self) self_weak_ = self;

    self_weak_是弱化后的self。 @weakify(self)就这么实现了。

    再看看strongify

    #define strongify(...)

        rac_keywordify

        _Pragma("clang diagnostic push")

        _Pragma("clang diagnostic ignored "-Wshadow"")

        metamacro_foreach(rac_strongify_,, __VA_ARGS__)

        _Pragma("clang diagnostic pop")

    rac_keywordify

    和之前同理,只是为了前面必须加@。

    _Pragma语句

    _Pragma("clang diagnostic push")

    _Pragma("clang diagnostic ignored "-Wshadow"")

    _Pragma("clang diagnostic pop")

    可能有人会不太了解_Pragma是什么,其实大家都用过它的前身:

    #pragma xxxx xxxx

    换过来就是:

    #pragma clang diagnostic push

    #pragma clang diagnostic ignored "-Wshadow"

    #pragma clang diagnostic pop

    这里的clang语句的作用:忽略当一个局部变量或类型声明遮盖另一个变量的警告 clang的对照表可以看fuckingclangwarnings

    http://fuckingclangwarnings.com/

    metamacro_foreach

    拿@strongify(self)打比方,metamacro_foreach(rac_strongify_,, self)

    #define metamacro_foreach(MACRO, SEP, ...)

            metamacro_foreach_cxt(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__)

    即:

    metamacro_foreach_cxt(metamacro_foreach_iter,,rac_strongify_,self)

    metamacro_foreach_cxt

    #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)

    #define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)

    即:

    metamacro_foreach_iter(0, rac_strongify_, self)

    metamacro_foreach_iter

    #define metamacro_foreach_iter(INDEX, MACRO, ARG) MACRO(INDEX, ARG)

    即:

    rac_strongify_(0,self)

    rac_strongify_

    #define rac_strongify_(INDEX, VAR)

        __strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_);

    即:

    __strong __typeof__(self) self = self_weak_;

    这个时候你在项目中敲入:

    __weak __typeof__ (self) self_weak_ = self;

    __strong __typeof__(self) self = self_weak_;

    你会发现你有一个错误,Redefinition of 'self',重新定义了自己。 一定要注意__strong __typeof__(self) self = self_weak_只能在block里面用。

        

    __weak __typeof__ (self) self_weak_ = (self);

        RootViewController * rootVC = [[RootViewController alloc]init];

        [rootVC setBlock:^{

            __strong __typeof__(self) self = self_weak_;

        }];

    RAC写法:

        @weakify(self)

        RootViewController * rootVC = [[RootViewController alloc]init];

        [rootVC setBlock:^{

            @strongify(self)

        }];

    后记

    对宏的运用来说,可以说,RAC的作者是我目前见过最强的。 本以为剖析起来应该花不了多少功夫,可是着实绞尽脑汁了。 我尽量捋清思路,但也就这样了..大家将就着看吧.. 要是有哪里不对或者不好,欢迎指出!

  • 相关阅读:
    Spark学习笔记2(spark所需环境配置
    Spark学习笔记1(初始spark
    zookeeper基本讲解及基本命令和配置 (转)
    计算机网络面试常考(转载)
    C++面试笔试题汇总
    复杂指针解析
    如何限制一个类对象只在栈(堆)上分配空间?
    虚函数实现机制
    C++内存分配方式详解
    C++中指针和引用的区别(转载)
  • 原文地址:https://www.cnblogs.com/fengmin/p/5497100.html
Copyright © 2020-2023  润新知