Block从入门到放弃宝典(二):循环引用

十一大家去哪happy了,不过去哪都是开启看人模式,这是block的第二篇文章,给大家简单剖析一些循环引用的问题,大家下一篇想看什么可以给楼主留言或私信,都会满足大家的

其实block是个双面剑,用好了可以使代码更简洁,增加可读性,但是往往大家忽略了循环引用的问题,所以还是希望大家要知其一,更要知其二,本着实用性为主,还是从实际项目中给大家介绍几个经典的循环引用场景.

怎么造成循环引用

两个对象相互持有,谁也不释放谁,就造成循环应用了

循环引用.jpeg

循环引用场景(一)

typedef void(^block)();

@interface ViewController ()
@property (copy, nonatomic) block testBlock;
@property (copy, nonatomic) NSString *testString;

- (void)viewDidLoad {
    [super viewDidLoad];
    self. testBlock = ^(){
        NSString *str = self.blockString;
    };    
}

如何造成循环引用

这样会造成循环引用,因为self.testBlock和self.blockString互相都是强引用,导致互相都不释放,我画出两者的关系


循环引用场景一.png
解决方法
- (void)viewDidLoad {
    [super viewDidLoad];
    __weak typeof(self) weakSelf = self;
    self. testBlock = ^(){
        NSString *str = weakSelf.blockString;
    };    
}

原理:使用__weak来修饰self对象,使其在block中不被持有,破坏循环引用


打破循环引用.png

循环引用场景(二)

大家在使用网络请求的时候,经常会用到block,但是殊不知也有可能已经循环引用了
首先创建一个NetWorkTool,并写一个方法

@interface NetWorkTools : NSObject
-(void)netWorkWithUrl:(void(^)(NSString *urlStr))urlStr;
@end
@interface NetWorkTools ()
@property (nonatomic, copy) void (^finishedBlock)(NSString *);
@end

-(void)netWorkWithUrl:(void(^)(NSString *urlStr))urlStr{
    // 1. 使用属性记录 block
    self.finishedBlock = urlStr;
}

在ViewController来调用这个类

@interface SecViewController ()
@property(nonatomic,strong)NetWorkTools *tool;
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    NetWorkTools *tool = [[NetWorkTools alloc] init];
    self.tool = tool;
    [self.tool netWorkWithUrl:^(NSString *urlStr) {
        self.view.backgroundColor = [UIColor whiteColor];
    }];
}
如何造成循环引用
循环引用场景2.png
解决方法
@interface SecViewController ()
@property(nonatomic,strong)NetWorkTools *tool;
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    __weak typeof(self) weakSelf = self;
    NetWorkTools *tool = [[NetWorkTools alloc] init];
    self.tool = tool;
    [self.tool netWorkWithUrl:^(NSString *urlStr) {
        weakSelf.view.backgroundColor = [UIColor whiteColor];
    }];
}

写在最后

其实有的时候并没有造成循环引用,举个例子

//这个是GCD的延迟调用方法,并没有造成循环引用
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.view.backgroundColor = [UIColor whiteColor];
    });

所以分析是不是循环引用还是多在项目中实践,坑踩得多了自然就懂了,虽然我这个方法很不可取

附上demo地址

推荐阅读更多精彩内容