@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