如何快速定位没调用dealloc的问题

Keywords :内存泄露,循环引用

前言

最近做项目碰到两次内存泄露的问题,一个是UIViewController的内存泄露问题,一个是UIView的,也就是没调用dealloc方法。这种bug解决多了,自己总结了一套方法。避免以后再花费更多的时间在这类问题上。希望大家多多补充,共勉之。

快速解决问题

1.持有UIView的UIViewController被正常释放了吗

如果你不是在定位UIView的泄露问题。请跳过此步骤。
自定义了一个UITableViewCell,按理来说在UIViewController退出后,UITableView会被销毁,自然UITableViewCell也会被释放。但是,我发现我的并没有。找了很久,才发现不是自定义的cell问题。而是相关的UIViewController就没有被释放。解决完UIViewController 的泄露问题,一切都迎刃而解了。所以,建议大家先定位上层UIViewController有没有被释放。若有,则肯定就是该UIView的问题了。

2.block的循环引用问题

感觉90%的泄露都是block的循环引用引起的。self是retain类型,会使引用计数加一,如果self又强持有这个block,那泄露问题就产生了。看下面的错误示例代码:

[self.testView setTestBlock:^(BOOL  finish) {
    [self doSomething];
}];

这里应该使用self的弱引用。正确代码如下:

__weak __typeof(&*self)weakSelf = self;
[self.testView setTestBlock:^(BOOL  finish) {
    [weakSelf doSomething];
}];

这样就解决了循环引用,就不会存在内存泄露了。
ps:多说一句,并不是所有的block中有必须要使用weakSelf这种弱引用。如果self并不持有该block,就不会有循环引用的问题,放心大胆的用strong self就行了。

3.使用strong 修饰属性delegate

Class A:
@property (nonatomic, strong) id delegate;

当设置A的代理为B时,A对B强引用。如果B对A也存在强引用,又产生了循环引用!!!所以当A没被释放时,不妨先把代理设置为weak属性。当然,并不是所有的delegate都会产生循环引用。当你不确定时,最好还是使用weak 修饰delegate。

4.NSTimer

self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f
                                              target:self
                                            selector:@selector(someMethod)
                                            userInfo:nil
                                             repeats:YES];
[self.timer setFireDate:[NSDate dateNow]];

当NSTimer开始正常工作之后,该UIViewController引用计数就被加一了。在页面消失的时候,应该先使NSTimer不工作,最好再置为nil,UIViewController才会调用dealloc方法。

 if (self.timer && [self.timer isValid]) {
    [self.timer invalidate];
    self.timer = nil; // 不置为nil也行
};

综上,希望大家保持写代码的好习惯,避免大量的内存泄露。

你可能感兴趣的:(如何快速定位没调用dealloc的问题)