@weakify, @strongify

作者: Stark_Dylan | 来源:发表于2015-07-03 20:38 被阅读22763次

    今天来讲weakify strongify。

    首先看一下实现的方式:

    方式1: 传统写法:

    #ifndef weakify
    #if __has_feature(objc_arc)
    
    #define weakify( x ) \\
    _Pragma("clang diagnostic push") \\
    _Pragma("clang diagnostic ignored \\"-Wshadow\\"") \\
    autoreleasepool{} __weak __typeof__(x) __weak_##x##__ = x; \\
    _Pragma("clang diagnostic pop")
    
    #else
    
    #define weakify( x ) \\
    _Pragma("clang diagnostic push") \\
    _Pragma("clang diagnostic ignored \\"-Wshadow\\"") \\
    autoreleasepool{} __block __typeof__(x) __block_##x##__ = x; \\
    _Pragma("clang diagnostic pop")
    
    #endif
    #endif
    
    #ifndef strongify
    #if __has_feature(objc_arc)
    
    #define strongify( x ) \\
    _Pragma("clang diagnostic push") \\
    _Pragma("clang diagnostic ignored \\"-Wshadow\\"") \\
    try{} @finally{} __typeof__(x) x = __weak_##x##__; \\
    _Pragma("clang diagnostic pop")
    
    #else
    
    #define strongify( x ) \\
    _Pragma("clang diagnostic push") \\
    _Pragma("clang diagnostic ignored \\"-Wshadow\\"") \\
    try{} @finally{} __typeof__(x) x = __block_##x##__; \\
    _Pragma("clang diagnostic pop")
    
    #endif
    #endif
    

    第二种: 装逼写法: 比如RAC

    #define weakify(...) \\
        autoreleasepool {} \\
        metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
    
    #define strongify(...) \\
        try {} @finally {} \\
        _Pragma("clang diagnostic push") \\
        _Pragma("clang diagnostic ignored \\"-Wshadow\\"") \\
        metamacro_foreach(rac_strongify_,, __VA_ARGS__) \\
        _Pragma("clang diagnostic pop")
    

    今天, 来解释一下RAC怎么实现这种装逼的写法。

    他们的作用主要是在block内部管理对self的引用:

    @weakify(self); // 定义了一个__weak的self_weak_变量 
    [RACObserve(self, name) subscribeNext:^(NSString *name) { 
        @strongify(self); // 局域定义了一个__strong的self指针指向self_weak 
        self.outputLabel.text = name; 
    }]; 
    

    这个宏为什么这么吊,前面加@,其实就是一个啥都没干的@autoreleasepool {}前面的那个@,为了显眼罢了。 还有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
    

    到最后, 才tm的发现, 这不就是个C语言中组合运算符的么, 把2个运算符组合成为1个运算符。 然后回过头看, 他就是吧__weak 以及第二步骤中#define rac_weakify_(INDEX, CONTEXT, VAR) \\ CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);的typedef拼接进去- - , 妈的 这都要装逼。。。。

    这两个宏一定成对出现,先weak再strong.可以很好的管理Block内部对self的引用。 当然你如果是一个不爱用黄色宏的屌丝的话、 你可以用原生代码写出来

        __weak typeof(self) weakSelf = self;
        self.Button.rac_command = [[RACCommand alloc] initWithEnabled:textSig signalBlock:^RACSignal *(NSString * input) {
           
            __strong typeof(weakSelf) strongSelf = weakSelf;
            return nil;
        }];
    

    原文地址http://www.cocoachina.com/industry/20140621/8905.html
    越是细节的东西, 越注定成败。 @Dylan.

    相关文章

      网友评论

      • hahand:rac定义了20个metamacro_foreach_cxt+num的宏,就是为了支持宏的动态参数,看完之后对他的思路有些佩服,但是宏名真的又长又臭,看一半明白是干啥目的就没看了,真的费时费力费眼睛。
      • a945ba0d3099:rac的可以这样写连续n个,这个怎么解释呢?@weakify(self, view1, view2, view3);
        Stark_Dylan:@吕超 :smiley: 您有看过源码了吗?跟着写一遍,就知道了
      • 59c1601a7210:请问swift下怎么用@weakify, @strongify
        Stark_Dylan:Swift 下,就没有 weakify 和 strongify 一说了吧。

        而是[weak self]和[unowned self],如果你可以保证在块儿执行期间,self一定不会为空,就可以使用 `unowned` 关键字,如果崩溃了,那就是可能为空,使用 `weak` 关键字。

        ```swift
        {[weak self] in
        self.do....
        }
        ```
        xmb:同问
      • 4ad7d6e3c294:看到这里才是终于学习了!多谢作者!
      • 新地球说着一口陌生腔调:这种写法好麻烦啊?
        @weakify(self)

        为什么不能直接使用 __weak __typeof(self)weakSelf = self;
        xx明:@新地球说着一口陌生腔调 直接用__weak的话,如果block内多次使用weakSelf的话,除第一个weakSelf外,后面的值有可能被释放,即weakSelf=nil。而__strong能保证在block执行完毕后才释放,保证了block内部strongSelf有值。
      • tikeyc:使用后 后会警告,⚠️,这个怎么破?
        Ambiguous expansion of macro 'strongify'
      • 寂静的天空:然而我还是看不懂 mark 先
      • 付寒宇:想问下博主,一般来说在block外部一般会进行__weak 为了在block内部使用weakSelf不强引用, 但是为什么在内部会转回__strong 那不是会引起循环引用么
        Stark_Dylan:@付寒宇 就是strong一个东西等于当前的对象
        付寒宇:@WildDylan 我可以这么理解么,我在外部已经将self weak掉了,这时的self已经不会被引用计数+1,那么就算我在block里面strong他,他也不会引用计数+1,因为他已经不是那个self了?
        Stark_Dylan:@付寒宇
        @weakify 不会造成引用计数+1,防止解循环引用
        @strongify 保证block调用的时候,内部的对象不会释放
      • 谈Xx:想请教下block中使用, 但是我之后想继续正常 的使用self, 会有影响吗
        谈Xx:@WildDylan 是在外面weak的呀,然后block里面是strong的。 在block后面继续使用self呢, 不是被weak过么
        Stark_Dylan:@谈Xx 不会的 在block外边 weakify 在里边 strongify 之后可以继续使用self。
      • 二斤寂寞: __weak typeof(self) weakSelf = self;
        self.Button.rac_command = [[RACCommand alloc] initWithEnabled:textSig signalBlock:^RACSignal *(NSString * input) {

        __strong typeof(weakSelf) strongSelf = weakSelf;
        return nil;
        }];
        strongSelf 内部的这个unused啊,这个如何使用

        jonqinwu:@yuanyi__ 如果你用哪个宏 可以直接用self
        要是按照上面 那你就要用strongSelf了
        b4067f4d3883:@萧十一郎d 我也是unused,是不是在block里面所有self改为strongSelf就可以了啊,求解答。
      • 二斤寂寞:这个比装的的确高,整闷我了,我看了许久,还是没看明白擦,
      • 出门右转掘金见:楼主我是来看的他的用法的呀,不是来看他咋装b的....有点小失望~
        Stark_Dylan:@小小其实不太大 .... 我这里主要是提供了这个宏的写法
      • songgeb:"这个宏为什么这么吊,前面加@,其实就是一个啥都没干的@autoreleasepool {}前面的那个@,为了显眼罢了。"这句话在别的博文中也有看到,没有任何改动。
        Stark_Dylan:@MonsterSong 嗯 是这篇内容。 但是是否是在这里读到的记不清楚了。
        6eeebdf65572:@songgeb http://www.cocoachina.com/industry/20140621/8905.html 你说的这篇吧,14年的文章 .
        Stark_Dylan:@songgeb :yum::yum:这确实是出自我的白话文手笔、 如有雷同 我也不晓得...
      • 我不是GM:一直在纳闷加个autoreleasepool是干嘛的呢,原来。。。
      • UItachi:第二种装逼写法确实有点过头了,不过它的出处好像应该是libextobjc,只是很多用RAC的项目都用了这个。
        火星抄手:这逼格有点。。。
        Stark_Dylan:@UItachi yep 是rac的贡献者之一写的

      本文标题:@weakify, @strongify

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