IOS ViewControl无法释放(不走“-(void)dealloc”方法)&&ViewControl释放后内存值不下降
2016-11-08 13:56
1396 查看
首先我们来讨论一下Viewcontrol无法释放的问题
最近在项目运行时发现这个内存消耗不是一般的高
这里内存较高也是有原因的,因为我这里展示了一张高度有两个屏幕高度的UIImageView。
好的吧,图片比较大内存消耗高一点我也就忍了,可是我现在的问题是,在我完全退出当前显示图片的ViewControl时,竟然不走
这下问题就大了,我都退出了这个界面,怎么内存消耗还是不降啊?这样下去,我要是反复的点进这个界面,那这个内存消耗还得了。(当时注意到,在我反复进入这个页面的时候内存消耗不会再升高,还是保持在180的样子,可是没有考虑那么多,只怪自己菜)
归根结底,是因为当前控制器被某个对象强引用了,控制器的引用计数不为0,系统无法帮你释放这部分内存
以下是我找到的原因和解决方案:
1、控制器中NSTimer没有被销毁
当viewController中存在NSTimer时,需要特别注意,当调用
时,因为 target:self ,也就是引用了当前viewController,导致控制器的引用计数加1,如果没有将这个NSTimer 销毁,它将一直保留该viewController,无法释放,也就不会调用dealloc方法。所以,需要在viewWillDisappear之前需要把控制器用到的NSTimer销毁。
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,却也存在循环引用的问题。因为对于编译器来说,_obj就相当于self->_obj,所以上面的代码就会变成
另外,block 要用 copy修饰而且还有防止析构
4、当前类中的变量在其他类中使用
这个问题是需要慢慢检查的,当你要释放的页面中有变量在其他没有释放的页面中任然作用。那么,当前的页面就无法释放,原因也是就是引用计数的问题(我想可以考虑值传递)
5、我根据上面的方法也检查了我的代码,然并卵
好吧,我的问题其实很简单,应该是我刚开始就发现的,只是没有考虑。
绕了一大圈我们来看看我们界面内存消耗的源头,没错UIimageView。
我的项目里使用的是:
这就是问题的根源,[UIImage imageNamed:@”“]分配的图像系统会放到cache里面。而关于cache管理的规则就没有明确的介绍。由此看来[UIImage imageNamed:]只适合与UI界面中小的贴图的读取,而一些比较大的资源文件应该尽量避免使用这个接口。
我这里的解决方法是使用NSData
这样在页面释放时,NSData就会被释放,理所当然这回走到了
dealloc这里。
哈哈 这就是我的解救过程,供自己记录。
附加:
释放自定义的UIView
这是我今天(2016.11.15)在项目中无法找到UIView中无法释放的元素时,自己手动将UIView置为了nil,也达到了效果。(无可奈何之选)
最近在项目运行时发现这个内存消耗不是一般的高
这里内存较高也是有原因的,因为我这里展示了一张高度有两个屏幕高度的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 控制器POP后dealloc方法不走,通知监听无法移除的问题
- 使用dismissModalViewControllerAnimated 不调用dealloc 内存不释放解决方法
- ios菜鸟之路:uiscrollview和pagecontrol的使用方法
- easyUI 能完全释放内存解决方法
- IOS中过滤HTML标签&&WebView的三种常用的使用方法
- IOS-57-导致内存未释放的常见原因(现象:dealloc不执行等)
- 为何ViewController释放后不走dealloc
- SQL2008无法连接到.\SQLEXPRESS,用户'sa'登录失败(错误18456)图文解决方法 已成功与服务器建立连接,但是在登录过程中发生错误。 (provider: 共享内存提供程序, er
- MapView Control 无法获取窗口控件句柄解决方法
- iOS 内存中的ViewController释放
- IOS初级:UIScrollView & UIPageControl
- iOS UITextField InputAccessoryView & InputView的使用方法
- iOS中UITableView内容无法刷新的方法
- iOS中UIScrollView与UIPageControl 同步变化的方法
- iOS定时器应该在viewDidDisappear还是dealloc方法里调用invalidate方法
- vs2008 无法设置断点&设置内存断点的方法
- vs2008 无法设置断点&设置内存断点的方法
- 为何ViewController释放后不走dealloc
- IOS微博项目之UIScrollView&UIPageControl
- webview 无法释放内存