NSTimer 销毁问题 和 iOS中控制器的释放问题
俗话说的好,前人栽树后人乘凉,最近看了很多博文,不少博文提到了NSTimer的销毁问题, 之前我都没怎么注意,现在对照着文章一一实践发现坑还真不少。下面是我读到的几篇博文分享给大家
@啸笑天的NSTimer
@庞海礁的个人空间
@汪海的实验室「iOS 中的 NSTimer」
这几篇文章阐述了NSTimer的销毁问题,并且都给出解决方案
这里就提供一个简洁的方案,是由啸笑天提供的
+ (NSTimer *)ez_scheduledTimerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)())inBlock repeats:(BOOL)inRepeats
{
void (^block)() = [inBlock copy];
NSTimer * timer = [self scheduledTimerWithTimeInterval:inTimeInterval target:self selector:@selector(__executeTimerBlock:) userInfo:block repeats:inRepeats];
return timer;
} + (NSTimer *)ez_timerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)())inBlock repeats:(BOOL)inRepeats
{
void (^block)() = [inBlock copy];
NSTimer * timer = [self timerWithTimeInterval:inTimeInterval target:self selector:@selector(__executeTimerBlock:) userInfo:block repeats:inRepeats];
return timer;
} + (void)__executeTimerBlock:(NSTimer *)inTimer;
{
if([inTimer userInfo])
{
void (^block)() = (void (^)())[inTimer userInfo];
block();
}
}
啸笑天解决方案的github地址
https://github.com/easyui/EZToolKit/blob/master/EZToolKit/EZCategory/NSTimer%2BEZ_Helper.m
提醒
上面的解决办法,只是解决了target的强引用问题,但是NSTimer销毁还是得自己在使用的viewController的dealloc方法中销毁
- (void)dealloc {
if ([self.timer isValid]) {
[self.timer invalidate];
self.timer = nil;
}
}
或者你有更好的办法,请拼命的@我
NSTimer的创建方式
创建方式有2种
1.这种创建方式,会主动添加到主循环中,即默认会执行,但当用户按住其他控件的时候,它就会停止执行,当放开控件,它才继续执行
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer ez_scheduledTimerWithTimeInterval:1.f block:^{
NSLog(@"nextPage");
[weakSelf nextPage];
} repeats:YES];
2.这种创建方式,不会主动添加到主循环中,得手动添加,有两种执行模式
NSRunLoopCommonModes 按住其它控件,不会停止执行
NSDefaultRunLoopMode 按住其它控件,会停止执行,和第一种方式一样
self.timer = [NSTimer ez_timerWithTimeInterval:1.f block:^{
NSLog(@"nextPage");
[weakSelf nextPage];
} repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
ARC工程是可以重写dealloc方法并被系统调用的,但不需要手动调用父类的dealloc,手写[super dealloc]方法会报错,事实上系统会自动帮你调用父类的dealloc方法,不需要你实现。可以通过在dealloc方法中打印log查看控制器是否被释放。
控制器在被pop后移出栈后会被释放,但有些时候会发现控制器出栈的时候不会调用dealloc方法,归根结底,是因为当前控制器被某个对象强引用了,控制器的引用计数不为0,系统无法帮你释放这部分内存。
控制器中NSTimer没有被销毁
当控制器中存在NSTimer时,就需要注意,因为当[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES];时,这个/target:self/ 就增加了VC的RetarnCountr, 如果你不将这个timer invalidate,就别想调用dealloc。需要在viewWillDisappear之前需要把控制器用到的NSTimer销毁。
[timer invalidate]; // 销毁timer
timer = nil; // 置nil
控制器中的代理不是weak属性
例如@property (nonatomic, weak) id<HCAppViewDelegate> delegate;代理要使用弱引用,因为自定义控件是加载在视图控制器中的,视图控制器view对自定义控件是强引用,
如果代理属性设置为strong,则意味着delegate对视图控制器也进行了强引用,会造成循环引用。导致控制器无法被释放,最终导致内存泄漏。
控制器中block的循环引用
block会把它里面的所有对象强引用(在ARC下)/PS:MRC下会retain加1/,包括当前控制器self,因此有可能会出现循环引用的问题。
即一个对象有一个Block属性,然而这个Block属性中又引用了对象的其他成员变量,那么就会对这个变量本身产生强应用,那么这个对象本身和他自己的Block属性就形成了循环引用。在ARC下需要修改成这样:(/也就是生成一个对自身对象的弱引用/)
__weak typeof(self) weakSelf = self;
即:保险起见block中所有的涉及到self的全给替换成weakSelf
参考链接:
1.https://github.com/piglikeYoung/Study-notes/wiki/NSTimer%E9%94%80%E6%AF%81%E9%97%AE%E9%A2%98
2.https://segmentfault.com/a/1190000003858306
3.http://blog.callmewhy.com/2015/07/06/weak-timer-in-ios/
4.http://www.jvaeyhcd.cc/2016/04/06/iOS%E4%B8%AD%E9%80%A0%E6%88%90dealloc%E4%B8%8D%E8%B0%83%E7%94%A8%E7%9A%84%E5%8E%9F%E5%9B%A0/
NSTimer 销毁问题 和 iOS中控制器的释放问题的更多相关文章
- iOS中控制器的释放问题
iOS中控制器的释放问题 ARC工程是可以重写dealloc方法并被系统调用的,但不需要手动调用父类的dealloc,手写[super dealloc]方法会报错,事实上系统会自动帮你调用父类的dea ...
- IOS中控制器的重要方法使用
1.屏幕即将旋转的时候调用(控制器监控屏幕旋转) - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfac ...
- iOS 中的 NSTimer
iOS 中的 NSTimer NSTimer fire 我们先用 NSTimer 来做个简单的计时器,每隔5秒钟在控制台输出 Fire .比较想当然的做法是这样的: @interface Detail ...
- iOS:iOS中的多控制器管理
iOS中的控制器有三种创建方式: 1.通过storyboard创建 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@" ...
- iOS中的NSTimer 和 Android 中的Timer
首先看iOS的, Scheduling Timers in Run Loops A timer object can be registered in only one run loop at a t ...
- IOS中的UINavigationController(导航控制器)
UINavigationController UINavigationControlle:导航控制器,是iOS中最常用的多视图控制器之一,它用来管理多个试图控制器 导航控制器可以认为是管理控制器的控制 ...
- iOS中多控制器的使用
通常情况下,一个app由多个控制器组成,当app中有多个控制器的时候,我们就需要对这些控制器进行管理. 在开发过程中,当有多个View时,可以用一个大的view去管理多个小的view,控制器也是如此, ...
- Swift - iOS中各种视图控制器(View Controller)的介绍
在iOS中,不同的视图控制器负责不同的功能,采用不同的风格向用户呈现信息.下面对各个视图控制器做个总结: 1,标准视图控制器 - View Controller 这个控制器只是用来呈现内容.通常会用来 ...
- iOS,视图控制器相关(UIViewController)
1.视图控制器各个方法调用时机 2.选项卡(Tab Bar)和导航栏(Navigation Bar) 3.有无控制器的页面跳转 4.页面跳转隐藏底部选项卡 5.获取导航栏和状态栏高度,隐藏导航栏返回按 ...
随机推荐
- matlab里plot画多幅图像、设置总标题、legend无边框
%%绘图 suptitle('公路') %总标题subplot(2,2,1);plot(x,y11,'r-') hold onplot(x,y21,'b-')xlabel('方向')ylabel(' ...
- Github命令详解
Git bash: ***创建本地版本库: $ cd d: $ mkdir git $ cd git $ mkdir test $ git init //初始化本地库 ***创建文件并添加到版本库 ...
- 写入XML文件
public static void writeXMLFile(Document doc,String xmlFileName) throws IOException{ OutputFormat f ...
- java运行时数据区域
数据区域有:程序计步器,虚拟机栈,本地方法栈,java堆,方法区 程序计步器: 它是一块较小的内存空间,它的作用可以看做是当先线程所执行的字节码的信号指示器. 每一条JVM线程都有自己的PC寄存器,各 ...
- 字符串:"2016-09-21T18:57:50+08:00[Asia/Chungking]" 转Date
public static void main(String[] args) throws Exception { Date date1 = new Date(); SimpleDateFormat ...
- Oracle sql 中的字符(串)替换与转换[转载]
1.REPLACE 语法:REPLACE(char, search_string,replacement_string) 用法:将char中的字符串search_string全部转换为字符串repla ...
- window.open打开新页面居中
var iHeight = 500;//新打开页面的高 var iWidth = 800;//新打开页面的宽 var iTop = (window.screen.height-30-iHeight)/ ...
- Zend Studio 无法打开的解决办法
今天郁闷的...正在写代码,突然 computer 嗝屁了,断电后自动重启了一次,开机后就悲剧了,Zend Studio 9 无法打开了,每次运行只弹窗个 请查看项目错误日志的提示 然后就没反应了.. ...
- JQ中的clone()方法与DOM中的cloneNode()方法
JQ中的clone()方法与DOM中的cloneNode()方法 cloneNode()定义和用法 cloneNode()方法创建节点的拷贝,并返回该副本. 语法: node.cloneNode(de ...
- js---DOM元素节点
创建新的 HTML 元素如需向 HTML DOM 添加新元素,您必须首先创建该元素(元素节点),然后向一个已存在的元素追加该元素. 实例1: <!DOCTYPE html> <htm ...