zoukankan      html  css  js  c++  java
  • 剖析RAC中的@weakify、@strongify

    需要:pod 'YYKit'

    在block语句块中,如果需引用self,而self对象中又持有block对象,就会造成循环引用循环引用(retain cycle),导致内存泄露,比如以下代码

    self.block = ^{
    
            [self description];
        };

    一般我们是这么解决的,使用一个__weal修饰的weakSelf变量指向self对象,在block中使用weakSelf:

     __weak typeof(self) weakSelf = self;
        self.block = ^{
    [weakSelf description]; };

    但是酱紫写,还是可能出问题,因为weakSelf是弱引用,而self一旦释放了,weakSelf可能为nil,还是举个栗子吧:
    先定义一个TestObj对象,他的属性有一个block对象

    @interface TestObj : NSObject@property (nonatomic, copy)void(^block)();@end@implementation TestObj- (void)dealloc {
        NSLog(@"%s",__func__);}- (instancetype)init {
        self = [super init];
        if (self) {
    
            __weak typeof(self) weakSelf = self;
            self.block = ^{
                dispatch_async(dispatch_get_global_queue(0, 0), ^{
                    [NSThread sleepForTimeInterval:1];
                    NSLog(@"%@",weakSelf);
                });
            };
        }
        return self;
    }
    
    @end

    执行testFunc方法,结果是打印的是(null),因为block里打印的方法是异步执行的,在 NSLog(@"%@",weakSelf);这句代码执行之前testFunc函数就结束,所以obj对象已经被release了。
    怎么解决呢?所以再对weakSelf做一次 __strong就可以了:

    __weak typeof(self) weakSelf = self;
            self.block = ^{
    
                __strong typeof(weakSelf) strongSelf = weakSelf;
                dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
                    [NSThread sleepForTimeInterval:1];
                    NSLog(@"%@",strongSelf);
                });
            };
    }

    使用了__strongstrongSelf变量作用域结束之前,对weakSelf有一个引用,防止对象(self)提前被释放。而作用域一过,strongSelf不存在了,对象(self)也会被释放。

    前面的写法虽然严谨了,也解决了问题了,但是作为喜欢偷懒的程序猿,会不会觉得很啰嗦?每次都要写那两条长长的__weak__strong,而且在block里用到的self的全部要改成strongSelf,假设把一段很多self的代码拷贝到block里,一个个改成strongSelf是不是很蛋疼?

    只要在block外用了@weakify(self);然后再block里写@strongify(self);就可以了,@strongify(self);语句后的的self可以原封不动,好像很神奇,下面一起看看@weakify、@strongify 这两个神奇的宏最终替换了什么东西。
    导入RAC的头文件,把上面的测试代码替换成RAC中用的@weakify(self);和@strongify(self), 分屏显示Xcode,让右侧的显示内容改为 preprocess“,就可以看到宏最终替换的结果。 

    再比如:

         @weakify(self);
            _topView.block = ^(NSInteger tag) {
                
                @strongify(self);
                
                CGPoint point = CGPointMake(tag * SCREEN_WIDTH, self.scrollView.contentOffset.y);
                [self.scrollView setContentOffset:point animated:YES];
            };
  • 相关阅读:
    编程能力与编程年龄
    编程能力与编程年龄
    通俗易懂,一篇文章告诉你编程语言是个啥?
    通俗易懂,一篇文章告诉你编程语言是个啥?
    进程与线程的区别:最浅显易懂的解释
    进程与线程的区别:最浅显易懂的解释
    为什么超 80% 的开源开发者苦苦挣扎在贫困线?
    java之异常处理
    33_java之类加载器和反射
    32_java之TCP和UDP
  • 原文地址:https://www.cnblogs.com/xuzb/p/8872006.html
Copyright © 2011-2022 走看看