首先解决循环引用
一. 基础控制器代码:
#import "ViewController.h"
/// 前两种解决循环引用
typedef void(^CPBlock)(void);
/// 用于第三种解决循环引用
typedef void(^CPParamBlock)(ViewController *);
@interface ViewController ()
/// 前两种解决循环引用示例
@property(nonatomic, copy) CPBlock block;
/// 用于第三种解决循环引用示例
@property(nonatomic, copy) CPParamBlock paramBlock;
@property(nonatomic, copy) NSString *name;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.name = @"CPBlock";
}
@end
二. Block循环引用示例代码
//1. self持有block
self.block = ^(void){
// block持有self
NSLog(@"%@", self);
// block持有self的属性name
NSLog(@"%@", self.name);
};
- 当self自身要释放的时候, 就需要先释放block,
- 要释放block, 就要先把执行体内部block对self的持有先释放,
- self的retainCount != 0, self.block的retainCount != 0, 两者永远不会被释放, 造成循环引用
三 敲重点 -- 解决循环应用
方法一. 弱引用方式解决循环应用代码 __weak
-(void)resolveRetainCycle_1{
__weak typeof(self) weakSelf = self;
self.block = ^(void){
NSLog(@"%@", weakSelf);
// 如果block执行体内有耗时操作, 或者异步操作, 那么我们还需要优化循环引用的解决方案
// strongSelf为block执行体内局部变量, 在block执行体范围内使用, 当block被释放, strongSelf也会被自动释放
__strong typeof(weakSelf)strongSelf = weakSelf;
// 以此异步延迟2秒任务模拟耗时操作
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@", strongSelf.name);
});
};
self.block();
}
方法二. 截获变量方式 __block
-(void)resolveRetainCycle_2{
// 截获当前ViewController
// 需要手动释放 vc = nil;
__block ViewController *vc = self;
self.block = ^(void){
// 以此异步延迟2秒任务模拟耗时操作
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@", vc.name);
vc = nil;
});
};
self.block();
}
方法三. 通讯传值方式
/// 解决循环引用方法三
-(void)resolveRetainCycle_3{
// 把self(实际为当前控制器: ViewController)作为一个临时变量传进block执行体
// 不会造成循环引用
self.paramBlock = ^(ViewController *vc){
// 以此异步延迟2秒任务模拟耗时操作
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@", vc.name);
});
};
self.paramBlock(self);
}
网友评论