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

首先我们来讨论一下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,也达到了效果。(无可奈何之选)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值