前言
视图控制器在退出的时候没有走dealloc,是因为当前控制器被某个对象强引用了,在控制器pop的时候引用计数没有减为0,系统无法帮你释放这部分内存;我在leaks里面去运行,也没有发现内存泄漏的提示,这种对于我们内存优化这个点,肯定是过不去的,也是不允许的;接下来说说出现这个问题的三种情况!
1.block的循环引用问题
大多数的泄露都是block的循环引用引起的。self是retain类型,会使引用计数加一,如果self又强持有这个block,那循环引用就产生了。看下面的示例代码:
self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshBlock:^{
[self request];
}];
上面的示例,self持有了这个block,在块里面又持有了self,这样会形成一个保留环,导致循环引用。我们可以通过弱引用优化这部分代码:
__weak typeof(self) weakSelf = self;
self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshBlock:^{
[weakSelf request];
}];
这样就解决了循环引用,就不会存在内存泄露了。这里多说一句,并不是所有的block中有必须要使用weakSelf这种弱引用。如果self并不持有该block,就不会有循环引用的问题,放心大胆的用self就行了。
2.使用strong 修饰属性delegate
@property(nonatomic,strong) id <someDelegate>delegate;
注意:这个属性需定义成weak,而非strong,因为本对象与委托对象之间必须为“非拥有关系”(nonowing relationship)。如果声明属性的时候用strong将本对象与委托对象之间定为“拥有关系”,那么就会引入“保留环”。
3.NSTimer
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:@selector(someMethod)
userInfo:nil
repeats:YES];
target引用了self,如果在对象销毁的时候没有将timer销毁,也会导致dealloc方法不走。
if(self.timer && [self.timer isValid]) {
[self.timer invalidate];
self.timer =nil;
}
上面的代码最好在viewWillDisappear或者viewDidDisappear里调用,不宜在dealloc里面调用,下面引申一下在dealloc方法中应该做哪些操作!!!
=====================这是一条迷人的分割线======================
在dealloc方法中只释放引用并解除监听
对象在经历其生命期后,最终会为系统所回收,这是就要执行dealloc方法了。在每个对象的生命期内,此方法仅执行一次,也就是当保留计数降为0的时候。然而具体何时执行,则无法保证。也可以理解成:我们能够通过人工观察保留操作与释放操作的位置,来预估此方法何时执行。但实际上,程序库会以开发者察觉不到的方式操作对象,从而使回收对象的真正时机和预期的不同。我们决不应该自己调用dealloc方法。运行期系统会在适当的时候调用它。而且,一旦调用过dealloc后,对象就不再有效了,后续方法调用均是无效的。
在dealloc方法中做些什么呢?主要就是释放对象所拥有的引用,也就是把所有Objective-C对象都释放掉,ARC会通过自动生成的.cxx_destruct方法,在dealloc中为你自动添加这些释放代码。还有一件事,那就是把原来配置过的观测行为都清理掉。如果用NSNotificationCenter给此对象订阅过某种通知,那么一般应该在这里注销,这样的话,通知系统就不再把通知发给回收后的对象了,若是还向其发送,则必然会令应用程序奔溃。
注意在dealloc方法里,不要做其他事情!不要做其他事情!不要做其他事情!
结语:觉得有用的同学可以点个赞哦,一起学习,一起成长!
网友评论