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.获取导航栏和状态栏高度,隐藏导航栏返回按 ...
 
随机推荐
- Nginx redirect
			
if ($host != 'www.xxxxx.com' ) { rewrite ^/(.*)$ http://www.xxxx.com/$1 permanent; }
 - C++从函数返回指针
			
C++ 允许您从函数返回指针.为了做到这点,必须声明一个返回指针的函数,如下所示: int * myFunction() { . . . } 另外,C++ 不支持在函数外返回局部变量的地址,除非定义局 ...
 - spring HttpServletRequest 简介
			
前提:工作遇到controller中通过注解的方式注入 @Resourceprivate HttpServletRequest request;我们都知道spring 默认是单例,当遇到并发的时候线程 ...
 - jmeter里json path postprocessor的用法
			
后置处理器添加 json path postprocessor. 用处: 当前接口响应返回的json中提取内容,作为变量可以在不同的请求中传递. 如下,从登陆接口返回的json中提取user id,变 ...
 - xampp版本和具体的php,mysql版本的对应
			
在国外网上查找到具体的xampp版本与php,mysql版本的对应关系,特此记录.以便需要的人使用.原文链接如下: http://code.stephenmorley.org/articles/xam ...
 - Okhttp设置http缓存,在没有网络的情况下加载http缓存里面的内容
			
HTTP_CACHE_FILENAME为缓存地址根路径: private final String HTTP_CACHE_FILENAME = "HttpCache"; priva ...
 - 抢红包算法 java
			
抢红包的需求分析 抢红包的场景有点像秒杀,但是要比秒杀简单点.因为秒杀通常要和库存相关.而抢红包则可以允许有些红包没有被抢到,因为发红包的人不会有损失,没抢完的钱再退回给发红包的人即可.另外像小米这样 ...
 - express学习点滴- methodOverride
			
app.use(express.methodOverride());在app.js中可以看到这个中间件,去翻文档,几乎没有提到.一番寻找,整理如下. 作用是使用REST风格的http请求时,进行改写后 ...
 - Var x;---定义变量
			
变量定义有多种格式 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...
 - 前台图片上传展示JS(单张图片展示)
			
<script type="text/javascript"> //下面用于多图片上传预览功能 function setImagePreviews(aval ...