block代码块在开发中经常使用于异步开发,例如GCD就是提供block的异步块,同时在使用block的时候每每须要注意避免循环引用,而消除block循环引用就是靠__weak来实现,好比:git
__weak typeof(self) _self = self;
而后在block块中使用__weak的_self这样就避免了循环引用的问题。
同时为了保证在block块中self不被释放掉,每每在block块中添加__strong修饰的引用github
__strong typeof(_self) self = _self;
这样既避免了循环引用,同时也保障了block块中使用self的时候不被意外释放掉。app
__weak typeof(self) _self = self; [self xxxfunciotnCompletion:^(void){ __strong typeof(_self) self = _self; //使用self不会存在循环引用了 }];
同时还应该注意另一个细节问题,若是在异步的Completion:块尚未执行前self就被释放的问题, 由于block块在执行前是并无强引用self,此时self是可能被释放的;若是此时再使用self就应该注意nil可能引发的崩溃。
由于__strong typeof(_self) self = _self;只能保障若是此时self没有被释放那么在block块中使用self期间不会被释放, 这只是暂时性的强引用self, 随着block块的结束而释放。异步
present一个控制器BViewController,BViewController加载后去下载一张大图片,而后动态的添加这个图片到视图,图片定位使用约束定位,简略的场景以下动图:ide
潜在崩溃:在大图尚未下载完以前就dismiss控制器BViewController使其销毁,待图片下载完成回调执行添加约束时崩溃。测试
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. __weak typeof(self) _self = self; [[BigImageDownloader shareDownloader] requestBigImageWithUrl:@"BigImg" completion:^(UIImage * _Nonnull image) { __strong typeof(_self) self = _self; //建立一个UIImageView显示, 并添加水平居中约束 UIImageView *bigImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 80, 200, 200)]; bigImageView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:bigImageView]; bigImageView.image = image; //建立约束 [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:bigImageView attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f].active = YES; [NSLayoutConstraint constraintWithItem:self.topLayoutGuide attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:bigImageView attribute:NSLayoutAttributeTop multiplier:1.0f constant:-80.0f].active = YES; }]; }
进入controller后就开始去下载一个图片,而后把图片用约束的方式定位显示到按钮的上方;
崩溃路径:进入控制器后,在图片还没下载完前就dismiss控制器,使其销毁,待图片下载完成后崩溃
崩溃log:ui
2018-11-03 22:13:11.879093+0800 strongSelf[43867:2859446] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'NSLayoutConstraint for (null): Constraint must contain a first layout item'
根据以上信息,崩溃缘由为建立约束时的first layout item不能为null, 而在此例中的first layout item即为self.view,也就是说self.view为nil了,由于咱们在图片下载完成前就dismiss了也就被销毁了,因此self.view天然为nil了致使崩溃。spa
在使用block解决循环引用别忘记判断self是否为空。code
__weak typeof(self) _self = self; [self xxxfunciotnCompletion:^(void){ __strong typeof(_self) self = _self; if(!self) return; }];
测试demo在这里Github图片