您的位置:首页 > 移动开发 > IOS开发

IOS ViewControl无法释放(不走“-(void)dealloc”方法)&&ViewControl释放后内存值不下降

2016-11-08 13:56 1396 查看
首先我们来讨论一下Viewcontrol无法释放的问题

最近在项目运行时发现这个内存消耗不是一般的高



这里内存较高也是有原因的,因为我这里展示了一张高度有两个屏幕高度的UIImageView。

好的吧,图片比较大内存消耗高一点我也就忍了,可是我现在的问题是,在我完全退出当前显示图片的ViewControl时,竟然不走

- (void)dealloc
- {
-  ////
- }


这下问题就大了,我都退出了这个界面,怎么内存消耗还是不降啊?这样下去,我要是反复的点进这个界面,那这个内存消耗还得了。(当时注意到,在我反复进入这个页面的时候内存消耗不会再升高,还是保持在180的样子,可是没有考虑那么多,只怪自己菜)

归根结底,是因为当前控制器被某个对象强引用了,控制器的引用计数不为0,系统无法帮你释放这部分内存

以下是我找到的原因和解决方案:

1、控制器中NSTimer没有被销毁

当viewController中存在NSTimer时,需要特别注意,当调用

[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:)  userInfo:nil repeats:YES]


时,因为 target:self ,也就是引用了当前viewController,导致控制器的引用计数加1,如果没有将这个NSTimer 销毁,它将一直保留该viewController,无法释放,也就不会调用dealloc方法。所以,需要在viewWillDisappear之前需要把控制器用到的NSTimer销毁。

[timer invalidate]; // 销毁timer
timer = nil; // 置nil


2、viewController中的代理不是weak属性

例如@property (nonatomic, weak/assign) id delegate;代理要使用弱引用,因为自定义控件是加载在视图控制器中的,视图控制器view对自定义控件是强引用,如果代理属性设置为strong,则意味着delegate对视图控制器也进行了强引用,会造成循环引用。导致控制器无法被释放,最终导致内存泄漏。(善用XXX.delegate = self)

3、viewController中block的循环引用

在ARC下,block会把它里面的所有对象强引用,包括当前控制器self,因此有可能会出现循环引用的问题。比如viewController中有个block属性,在block中又强引用了self或者其他成员变量,那么这个viewController与自己的block属性就形成循环引用,导致viewController无法释放。

错误
self.tableView.mj_header= [MJRefreshNormalHeader headerWithRefreshingBlock:^{

[self pullDownAction];
}];
//由于self是__strong修饰,在 ARC 下,当编译器自动将代码中的 block 从栈拷贝到堆时,block 会强引用和持有self,而self恰好也强引用和持有了 block,就造成了传说中的循环引用。

正确

A、typeof(self) __weak weakSelf = self;
B、id __weak weakSelf = self;

self.tableView.mj_header= [MJRefreshNormalHeader headerWithRefreshingBlock:^{

[weakSelf pullDownAction];
}];


还有一个列子:

@interface MyObject : NSObject
{
myBlock  blk;
id _obj;
}
@end
@implementation MyObject

- (id)init
{
self = [super init];
blk = ^{ NSLog(@"_obj = %@", _obj); };
return self;
}
...
...
@end


上面的例子中,虽然没有直接使用 self,却也存在循环引用的问题。因为对于编译器来说,_obj就相当于self->_obj,所以上面的代码就会变成

blk = ^{ NSLog(@"_obj = %@", self->_obj); };


另外,block 要用 copy修饰而且还有防止析构

4、当前类中的变量在其他类中使用

这个问题是需要慢慢检查的,当你要释放的页面中有变量在其他没有释放的页面中任然作用。那么,当前的页面就无法释放,原因也是就是引用计数的问题(我想可以考虑值传递)

5、我根据上面的方法也检查了我的代码,然并卵

好吧,我的问题其实很简单,应该是我刚开始就发现的,只是没有考虑。

绕了一大圈我们来看看我们界面内存消耗的源头,没错UIimageView。

我的项目里使用的是:

NSString *path = [NSString stringWithFormat:@"%@/%@.png",RecordTempRoute,self.midiFile];
UIImageView * imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:path]];


这就是问题的根源,[UIImage imageNamed:@”“]分配的图像系统会放到cache里面。而关于cache管理的规则就没有明确的介绍。由此看来[UIImage imageNamed:]只适合与UI界面中小的贴图的读取,而一些比较大的资源文件应该尽量避免使用这个接口。

[UIImage imageWithContentsOfFile]


我这里的解决方法是使用NSData

NSString *path = [NSString stringWithFormat:@"%@/%@.png",RecordTempRoute,self.midiFile];
NSData *data=[NSData dataWithContentsOfFile:path];
UIImageView * imgView = [[UIImageView alloc] initWithImage:[UIImage imageWithData:data]];


这样在页面释放时,NSData就会被释放,理所当然这回走到了

dealloc这里。

哈哈 这就是我的解救过程,供自己记录。

附加:

释放自定义的UIView

[view removeFromSuperview];
view = nil;


这是我今天(2016.11.15)在项目中无法找到UIView中无法释放的元素时,自己手动将UIView置为了nil,也达到了效果。(无可奈何之选)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios