美文网首页
RAC中宏的解析

RAC中宏的解析

作者: lattr | 来源:发表于2017-12-29 23:15 被阅读110次

一入宏门深似海
从此迷路出不来

按照惯例先上代码

    @weakify(self)
    [[self.btn rac_signalForControlEvents:(UIControlEventTouchUpInside)] subscribeNext:^(__kindof UIControl * _Nullable x) {
        @strongify(self)
        self.label.text = @"hello";
    }];

这是RAC中最常用的宏的使用。大家都知道需要成对使用,可传多个参数,为什么呢?点开源宏(不是袁弘)进行分析。

#define weakify(...) \
    rac_keywordify \
    metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)

其中...代表可变参数,即可传入多个值,对应于上面的__VA_ARGS__。比如@weakify(self, _a, _b)编译时__VA_ARGS__就会替换为self, _a, _b。现在分成三个部分来解析上面的宏。

1.rac_keywordify

#if DEBUG
#define rac_keywordify autoreleasepool {}
#else
#define rac_keywordify try {} @catch (...) {}
#endif

这里比较简单,如果是DEBUG模式,就开启自动释放池,如果是release模式,就使用@try/@catch。作者在注释中说明了,这两种方式都是完美的,并且没有其他方式,之所以在DEBUG模式下使用自动释放池,是因为@try/@catch会影响XCode的警告功能,导致返回值的检查出问题。比如下面的例子,在release模式下,没有返回值,也不会出现编译错误。

@weakify(self);
self.block = ^BOOL {
  @strongify(self);
  NSLog(@"123");
};

所以,按@weakify(self, _a, _b)举例子,编译后的结果为@autoreleasepool {} metamacro_foreach_cxt(rac_weakify_,, __weak, self, _a, _b)

2.metamacro_foreach_cxt

#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
        metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)

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

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

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

#define metamacro_at(N, ...) \
        metamacro_concat(metamacro_at, N)(__VA_ARGS__)

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

#define metamacro_head(...) \
        metamacro_head_(__VA_ARGS__, 0)

#define metamacro_head_(FIRST, ...) FIRST

metamacro_foreach_cxt展开之后又出现两个宏metamacro_concatmetamacro_argcount。现在分别分析。

  • metamacro_concat
    A ## B的意思是连接A和B。比如metamacro_concat(n, 1)编译后为n1。
  • metamacro_argcount
    metamacro_argcount的作用是返回传入的可变参数的个数。
    展开为:
    ->metamacro_at(20, self, _a, _b, 20, 19, 18, 17, ···, 6, 5, 4, 3, 2, 1)
    由于20, self, _a, _b, 20, 19, 18, 17, ···, 6, 5, 4, 3, 2, 1_0, _1, _2, _3, _4, _5, _6, ···, _17, _18, _19, ...一一对应,而_0, _1, _2, _3, _4, _5, _6, ···, _17, _18, _19为20个固定参数,所以20, self, _a, _b, 20, 19, 18, 17, ···, 6, 5, 4这20个参数被固定参数所取代,所以只剩下3,2,1对应于...
    ->metamacro_concat(metamacro_at, 20)(self, _a, _b, 20, 19, 18, 17, ···, 6, 5, 4, 3, 2, 1)
    ->metamacro_at20(self, _a, _b, 20, 19, 18, 17,···, 6, 5, 4, ...) metamacro_head(3, 2, 1)
    ->metamacro_at20(self, _a, _b, 20, 19, 18, 17,···, 6, 5, 4, ...) metamacro_head(3, 2, 1)
    ->metamacro_head_(3, 2, 1, 0)
    ->3
    所以如果按@weakify(self)为例,metamacro_argcount(self)返回的结果为1
    metamacro_foreach_cxt(rac_weakify_,, __weak, self, _a, _b)就可简化为
    ->metamacro_concat(metamacro_foreach_cxt, 3)(MACRO, SEP, CONTEXT, __VA_ARGS__)
    ->metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, __VA_ARGS__)
    ->metamacro_foreach_cxt3(rac_weakify_,, __weak, self, _a, _b)
#define metamacro_foreach_cxt0(MACRO, SEP, CONTEXT)
#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)

#define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
    metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \
    SEP \
    MACRO(1, CONTEXT, _1)

#define metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \
    metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
    SEP \
    MACRO(2, CONTEXT, _2)

由于SEP这个参数传的是空,所以该参数可忽略不计。根据上面的宏定义
->metamacro_for_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2)
->metamacro_for_cxt2(MACRO, SEP, CONTEXT, _0, _1) MACRO(2, CONTEXT, _2)
->metamacro_for_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(1, CONTEXT, _1) MACRO(2, CONTEXT, _2)
->MACRO(0, CONTEXT, _0) MACRO(1, CONTEXT) MACRO(2, CONTEXT)
->rac_weakify_(0, __weak, self) rac_weakify_(1, __weak, _a) rac_weakify_(2, __weak, _b)

3.rac_weakify_

#define rac_weakify_(INDEX, CONTEXT, VAR) \
    CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);

所以继续转化
->CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR)
->__weak __typeof__(self) metamacro_concat(self, _weak_) = (self)
->__weak __typeof__(self) self_weak_ = (self)
所以得到最终结果:
->rac_weakify_(0, __weak, self) rac_weakify_(1, __weak, _a) rac_weakify_(2, __weak, _b)
->__weak __typeof__(self) self_weak_ = (self) __weak __typeof__(_a) _a_weak_ = (_a) __weak __typeof__(_b) _b_weak_ = (_b)

使用XCode验证结果如下:

       @autoreleasepool {} __attribute__((objc_ownership(weak))) __typeof__(self) self_weak_ = (self); __attribute__((objc_ownership(weak))) __typeof__(_a) _a_weak_ = (_a); __attribute__((objc_ownership(weak))) __typeof__(_b) _b_weak_ = (_b);
    [[self.btn rac_signalForControlEvents:(UIControlEventTouchUpInside)] subscribeNext:^(__kindof UIControl * _Nullable x) {
        @autoreleasepool {}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"
 __attribute__((objc_ownership(strong))) __typeof__(self) self = self_weak_; __attribute__((objc_ownership(strong))) __typeof__(_a) _a = _a_weak_; __attribute__((objc_ownership(strong))) __typeof__(_b) _b = _b_weak_;
#pragma clang diagnostic pop
 self.label.text = @"hello";
        _a = @"a";
        _b = @"b";
    }];

__weak经过LLVM会自动转化为__attribute__((objc_ownership(weak)))

相关文章

  • RAC中宏的解析

    一入宏门深似海从此迷路出不来 按照惯例先上代码 这是RAC中最常用的宏的使用。大家都知道需要成对使用,可传多个参数...

  • 小驴拉磨之—ReactiveCocao(RAC)一些重要的宏

    使用过RAC的都知道RAC的宏是非常强大的,在这我给大家介绍一些重要的宏。 元宏(RAC中最基本一个宏,PS:那个...

  • RAC使用

    RAC常用宏 KVO监听使用 RAC宏使用 信号类使用 使用信号模拟代理 rac_sequence遍历字典 解包元...

  • RAC 详细解析

    RAC详细解析(一)—— 框架概览RAC详细解析(二)—— 基础使用方法

  • ReactiveCocoa 之 @weakify/@strong

    @weakify 和 @strongify 是 RAC 中对于强弱引用操作的宏定义。 1. 拆解宏定义 下面的代码...

  • RAC(target,keypath,nilValue)宏解析

    我们经常使用这个宏来将对象的属性和一个信号signal绑定在一起,当signal改变,对象的属性也就被赋予相应的值...

  • RAC宏

    一、基础宏 1.metamacro_stringify 这样写的目的是预防参数中传入宏定以后,以宏定义的名字做为参...

  • Linux内核__setup()宏介绍

    Linux内核中可使用宏__setup()处理内核的启动参数cmdline的解析。 一、宏解析 文件:includ...

  • RAC一些常见用法(五)

    本demo详见github 1.常见的用法 2.RAC常见的宏 3.发送验证码 友情链接: RAC(一) RAC(...

  • ReactiveCocoa在swift情况下使用宏

    在swift的环境下,配置RAC和RACObserve宏需要另外添加文件,如下: 在学习swift导入RAC的过程...

网友评论

      本文标题:RAC中宏的解析

      本文链接:https://www.haomeiwen.com/subject/sddvgxtx.html