【iOS开发】内存管理之UIViewController无法正常释放的常见问题,iOS开发中内存管理是很重要的,如果处理不当,轻则会导致内存泄漏、莫名其妙的bug等等,重则可能导致程序崩溃。本文总结了在iOS开发中三个可能导致控制器不能正常释放的常见问题。
导致控制器不能正常释放的原因?
控制器的引用计数不为0,也就是说被其他对象强引用,因此不能正常释放。
如何知道控制器是否已经正常释放?
在ARC模式下,控制器在彻底销毁之前会调用dealloc方法,并自动调用[super dealloc]方法。因此,可以重写基类的dealloc方法,输出控制器销毁提示信息,如果控制器没有调用dealloc方法,说明不能正常释放。
- (void)dealloc { NSLog(@"%@ dealloc",NSStringFromClass([self class])); }
无弱引用声明的情况下,block持有它里面所有对象的所有权,即为强引用,所以当在block里面使用self的时候,可能会导致控制器不能正常释放。
比如:objectB拥有callbackBlock属性,在objectA中设置该属性
[objectB setCallbackBlock:^{ [self excuBlock]; }];
在block中引用了自身方法(或变量),形成了循环引用。
解决方法:
在block中使用对自身对象的弱引用来替换self
__weak __typeof(self)weakSelf = self; [objectB setCallbackBlock:^{ __strong __typeof(weakSelf)strongSelf = weakSelf; [strongSelf excuBlock]; }];
如果在block使用了成员变量,也要使用其弱引用,以 _dataSource为例:
__weak typeof(_dataSource) weakDataSource = _dataSource;
如果一个delegate属性的声明是strong的时候,会持有自身控制器的所有权,导致控制器不能正常释放。
比如:
CustomView的delegate声明 @property (nonatomic, strong) iddelegate; 在控制器中赋值 self.customView.delegate = self; 这样,造成self对customView强引用,customView对self强引用,引发循环引用。 解决方法: 对代理使用弱引用 @property (nonatomic, weak) id delegate;
当我们使用NSTimer的方法
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes];
时,定时器对象会对它的target(即self:当前控制器)持有强引用,如果定时器不销毁,则控制器无法释放。
解决方法:
在- (void)viewWillDisappear:(BOOL)animated或者- (void)viewDidDisappear:(BOOL)animated或者其他确定离开当前控制器的方法中销毁定时器。
- (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; if (self.timer != nil) { [self.timer invalidate]; self.timer = nil; } }