我们新建一个NewViewController
,在开始的ViewController
写如下代码
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(100, 100, 100, 50);
btn.backgroundColor = [UIColor brownColor];
[btn addTarget:self action:@selector(jump) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
-(void)jump{
NewViewController *newVC = [[NewViewController alloc]init];
[self presentViewController:newVC animated:YES completion:nil];
}
然后在NewViewController
里:
-(void)dealloc{
NSLog(@"--------------dealloc");
}
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(100, 300, 100, 50);
btn.backgroundColor = [UIColor brownColor];
[btn addTarget:self action:@selector(jump) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self log];
NSLog(@"--------------after");
});
}
-(void)log{
NSLog(@"--------------log");
}
-(void)jump{
NSLog(@"--------------dismiss");
[self dismissViewControllerAnimated:YES completion:nil];
}
运行之后,我们一跳进newVC里面返回,这时候:
image.png
结果说明我们dismiss的时候,newVC还没有被释放,dealloc
方法在dispatch_after
延迟方法执行之后才会走,原因就是dispatch_after
强引用了self(即newVC)
,等强引用过去,self
才能得到释放走dealloc
。
接下来,我们在dispatch_after
里把 self 用 __weak
修饰,block里把self
改为weakself
,我们还是一样的操作流程,看看结果:
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(100, 300, 100, 50);
btn.backgroundColor = [UIColor brownColor];
[btn addTarget:self action:@selector(jump) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakSelf log];
NSLog(@"--------------after");
});
}
image.png
当我们用weak修饰self时,dispatch_after
并没有强引用self
,所以我们dissmiss
时,dealloc
立马就会走,然后10s后,dispatch_after
的执行函数还是会执行,输出了after,但是没有输出log,这是因为用的weakSelf
,dissmiss
后,newVC已经被释放,这时候代码 [weakSelf log];
等同于[nil log];
,所以才不会输出log。
使用注意
虽然dispatch_after
里直接调用self
不会造成循环引用,但当我们dispatch_after
延迟时间过长的时候,需要考虑是否要及时释放当前对象,如果需要,尽量使用weakSelf
这种方式,如果真有需要用到self完成一些操作再释放的需求,可以按需编写代码。