ios在开发的过程中,很容易引发内存泄露问题。也很容易造成循环引用,之前使用block的时候也没有过多注意,其实坑很多。 对于新手来说,出现循环引用的时候,很难去排查。
Controller之间的block循环引用
现在,我们声明两个类,一个是ViewController,另一个是TLController,在ViewController中有个按钮,点击 push到TlController中。 先看TLController中类的声明:
1 2 3 4 5 6 |
|
TlController.m
1 2 3 4 5 6 7 |
|
为了验证该类是不是被释放掉了,我们重写两个方法来检测:
1 2 3 4 5 6 7 |
|
在 ViewController中,创建一个按钮,按钮的单击事件如下:
1 2 3 4 5 6 7 8 9 10 |
|
现在看Viewcontroller,这里就形成了两个循环,因此vc属性得不到释放,如图:
这里形成了两个循环
ViewContrller->强引用了vc->强引用了callback->强引用了Viewcontroller
Viewcontroler->强引用了属性vc->强引用了callback->强引用了Viewcontroller的属性button
我们要解决这两个循环引用,可以如下操作:
不声明vc属性,或者将vc属性声明为weak弱引用类型,在callback回调处,将self.button改为 weakSelf.button,也就是让callback的这个block对viewcontroller弱引用,这样内存就可以顺利释放了。
1 2 3 4 5 6 7 8 9 10 |
|
Controller和View之间的block引用
我们先定义一个view,用于和Contrller交互,当点击view上的按钮时,就把结果回调给controller;
TLView定义如下: TlView.h
1 2 3 4 5 |
|
TlView.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
接下来,在TlController中增加两个属性
@property (nonatomic, strong) TLView *aView;
@property (nonatomic, strong) id currentModel;
调用如下:
-(void)testView{
// __weak __typeof(self) weakSelf=self;
self.aView = [[TLView alloc] initWithBlock:^(id model) {
// 假设要更新model
self.currentModel = model;
//weakSelf.currentModel=model;
}];
// 假设占满全屏
self.aView.frame = self.view.bounds;
[self.view addSubview:self.aView];
self.aView.backgroundColor = [UIColor whiteColor];
}
在viewDidLoad方法中,调用[self testView]
这样Controller和view之间就形成了循环引用,如图:
- TlViewController->强引用aView->block->tlViewcontroller属性的currentModel
解决的办法是:在创建aView的时候,block内对currentModel的引用改成弱引用
__weak __typeof(self) weakSelf=self;
self.aView = [[TLView alloc] initWithBlock:^(id model) {
// 假设要更新model
weakSelf.currentModel=model;
}];
很多程序员直接使用currentModel,其实这样也会造成循环引用,因为currentModel也是属于类的成员变量,也会被强引用的。要解决此问题,也要改成弱引用
__block __weak __typeof(_currentModel) weakModel = _currentModel;
self.aView = [[TLView alloc] initWithBlock:^(id model) {
// 假设要更新model
weakModel = model;
}];
模拟循环引用
1 2 3 4 5 6 |
|
aVC->强引用了bVC
bVC->强引用了aVC
如果是这样引用,就形成环了。aVC->bVC->aVC,这就形成了环。
如果一个Controller中,存在一个局部变量,是否循环引用呢?
在Viewcontroller中声明一个变量
@property (nonatomic,strong)NSMutableArray *array;
1 2 3 4 5 6 7 |
|
点击跳转按钮,控制台打印
BlockDemo1[5511:1169090] 进入控制器:TLController
2016-03-04 14:08:45.612
点击回退,控制台打印
BlockDemo1[5511:1169090] 控制器被dealloc: TLController
说明成员变量NSMutableArray不会形成循环引用。