object-c编程tips-timer
object-c定时器
object-c定时器会自己主动retain当前的使用者,假设不注意调用invalidate,则非常easy引起循环引用导致内存泄露。以下的思路提供了一套还算可行的解决方式。
举例:
常常在viewController中有可能有自己主动刷新界面的需求。 获取数据失败后。每隔10秒自己主动刷新又一次获取数据,这个时候使用NSTimer是一个非常方便的事情。普通情况下直接创建一个NSTimer的repeat对象,然后实现相应的timerFireMethod方法。 当用户主动点击返回button时候,此界面应该被释放。可是因为NSTimer retain了当前的viewController,导致界面内存泄露。 你可能会说在dealloc中调用invalidate,可是必须明确dealloc根本就不会调用,当然viewDidDisappear也一样不会被调用。
前一段时间看了effective object-c,学习了一种非常好的思想,现分享出来。
给NSTimer加入一个类别,使用block的方式传递timerFireMethod。代码例如以下:
@implementation NSTimer(LPBLocks) +(NSTimer*) lpScheduleTimerWithTimerInternal:(NSTimeInterval)interval
block:(void(^)())block
repeats:(BOOL)repeats
{
return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(lpTimerBlockInvoke:) userInfo:[block copy] repeats:repeats];
}
+(void)lpTimerBlockInvoke:(NSTimer*)timer
{
void(^block)() = timer.userInfo; if(block){
block();
}
}
@end
这个scheduledTimer方法也会retain target,可是因为这是一个类方法。它保留的是类对象,因此也就不会有什么问题。
它传入要运行的block, 然后在回调函数中通过userInfo得到block,并运行。
改进:
这个已经是一个非常大的改进了。我们能够在代码中放心的传入block代码。只是细致思考一下。假设在block中引入了viewController的成员,并且timer又作为成员变量存在于viewController中。
比如例如以下的代码:
@interface LPNextViewController ()
{
NSTimer* refreshTimer;
}
这样viewController和refreshTimer又陷入了循环引用的逻辑圈里。当然能够在block中使用weak_self的方式避免循环引用,可是写起代码来总是有些不顺手。并且还必需要外部使用者显式的进行。
于是非常easy想到。应该封装到一个专门的LPTimer类中。它负责持有NSTimer。同一时候NSTimer的block使用LPTimer的weak版本号。
@interface LPTimer ()
{
NSTimer* _pollTimer; //timer selector
__weak id _weak_target;
SEL _selector;
id _userInfo;
}
@end
-(void)scheduleTimerWithTimerInternal:(NSTimeInterval)interval
target:(id)target
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)repeats
{
__weak id weak_self = self; _weak_target = target;
_selector = aSelector;
_userInfo = userInfo; //借用第一个版本号的block思想
//使用了第二层间接,调用_weak_target的aSelector方法。
//这样能够把stopTimer给封装进去。外部不须要管理timer的stop。
_pollTimer = [NSTimer lpScheduleTimerWithTimerInternal:1 block:^{
[weak_self doTimer];
} repeats:repeats];
}
上面的代码LPTimer持有NSTimer对象。而NSTimer运行的block使用的是weak_self。
它在timer触发的时候调用自身的doTimer方法。在doTimer中负责将方法传递给外部的使用者。
-(void)doTimer
{
if ([_weak_target respondsToSelector:_selector]) {
[_weak_target performSelector:_selector withObject:self];
}
else{
DLog(@"WARNNING: unknown selector");
}
}
_weak_target是外部的使用者。 外部的使用者能够将LPTimer看成是一个普通的对象即可,持有它也不会有什么问题。 LPTimer保留一个弱引用指向外部的使用者。在时间到timer触发的时候,会先调到NStimer的block中。然后传递到LPTimer的doTimer中。然后调用到_weak_target的selector中。
必须注意释放NStimer对象,在LPTimer释放的时候调用NSTimer的invalidate方法。
-(void)stopTimer
{
DLog(@"");
[_pollTimer invalidate];
}
-(void)dealloc
{
[self stopTimer];
DLog(@"");
}
事实上。使用者都是使用的LPTimer类,那么应该让LPTimer表现的和NSTimer的行为一模一样, 使用组合方式的适配器模式就能够轻松搞定。
总结:
主要的思想就是NSTimer会retain一个对象,如今让它retain类对象。
当时候到来进行触发的时候,由NSTimer类对象触发到Block中。继而触发到外部的LPTimer普通对象中。
在普通对象中我们就能够自由的进行处理了。使用weak_target使LPTimer弱引用外部使用者,断开外部使用者与LPTimer的关联。
使用weak_self断开LPTimer与NStimer的循环关联。 个人觉得还算不错的思想, 有须要的欢迎讨论。
object-c编程tips-timer的更多相关文章
- Java并发编程:Timer和TimerTask(转载)
Java并发编程:Timer和TimerTask(转载) 下面内容转载自: http://blog.csdn.net/xieyuooo/article/details/8607220 其实就Timer ...
- Java并发编程:Timer和TimerTask
Java并发编程:Timer和TimerTask 下面内容转载自: http://blog.csdn.net/xieyuooo/article/details/8607220 其实就Timer来讲就是 ...
- 16、Java并发编程:Timer和TimerTask
Java并发编程:Timer和TimerTask(转载) 下面内容转载自: http://blog.csdn.net/xieyuooo/article/details/8607220 其实就Timer ...
- Java编程Tips
原文: Java编程中"为了性能"尽量要做到的一些地方 作者: javatgo 最近的机器内存又爆满了,除了新增机器内存外,还应该好好review一下我们的代码,有很多代码编写过于 ...
- [C++]高效C/C ++编程tips
Effective C++ 视C++ 为一个语言联邦(C.Object-Oriented C++.Template C++.STL) 宁可以编译器替换预处理器(尽量以const.enum.inline ...
- 编程Tips集锦
以下是自己编程的一些小贴士,记录,总结提高自己. 1.python中集合类型的查找,尽量用dict or set类型. dict和set类型,在python内部的实现都是使用hash映射,查找的时间复 ...
- 前端编程tips
1.ts less 网上搜视频教程,不用太复杂的,短短几分钟视频基本就对其入门了,比自己搜官网学习更方便. 常用的ts技术:let name:string=""; let obj ...
- 编程Tips
三元运算符 Vb中的iif(expr,truepart,falsepart)和C#中的expr?truepart:falsepart. 无论expr的结果是true还是false,true/false ...
- stm8编程tips(stvd)
编译完成时显示程序占用的flash和ram大小 将附件压缩包中的mapinfo.exe解压到stvd的安装路径\stvd中 在工程上点右键选settings 右侧的选项卡选择Linker,将categ ...
- C#中Timer使用及解决重入问题
C#中Timer使用及解决重入问题 ★介绍 首先简单介绍一下timer,这里所说的timer是指的System.Timers.timer,顾名思义,就是可以在指定的间隔是引发事件.官方介绍在这里,摘抄 ...
随机推荐
- Hadoop源代码导入Eclipse
须要进一步学习hadoop.须要看看内部源代码实现.因此须要将hadoop源代码导入都eclipse中,简单总结一下,详细过程例如以下: 首先确保已经安装了git.maven3.protobuf2.5 ...
- Cocos2d-x使用android拍照功能加载照片内存过大,通过另存照片尺寸大小解决
使用2dx调用android拍照功能,拍照结束后在2dx界面显示拍照照片,如果不对照片做处理,会出现内存过大的问题,导致程序崩溃,如果仅仅另存拍照照片,则照片质量大小均下降,导致照片不够清晰,后来发现 ...
- 深入理解maven与应用(二):灵活的构建
深入理解maven及应用(一):生命周期和插件 參考官方url:http://maven.apache.org/guides/index.html 一个优秀的构建系统必须足够灵活,应该可以让项目在不同 ...
- Delphi中拖动无边框窗口的5种方法
1.MouseMove事件中加入: // ReleaseCapture;// Perform(WM_SYSCOMMAND, $F017 , 0); 2.MouseDown事件中加入: // POSTM ...
- MFC 关于对话框的注意点
1.对于模态对话框而言,单击确定以后对话框窗口对象即被销毁了,而对于非模态对话框来说,对话框的对象并未销毁而是隐藏起来(EndDialog函数),因此对于非模态对话框,必须重写OnOK这个虚函数,并在 ...
- Phalcon资源文件管理(Assets Management)
资源文件管理(Assets Management)¶ Phalcon\Assets是一个让开发人员管理静态资源的组件,如管理css,javascript等. Phalcon\Assets\Manage ...
- Tomcat 用户配置
如果你没有改变任何配置文件,请检查文件conf / tomcat用户.xml在你安装.该文件必须包含凭证让你使用这个应用. 例如,添加一个用户名为tomcat manager gui角色s3cret密 ...
- 关于WM_ERASEBKGND和WM_PAINT的深刻理解
一直以来,对于WM_PAINT和WM_ERASEBKGND消息不是很清楚,从书上和网上找了很多资料,大体上有以下几点说法:1>WM_PAINT先产生,WM_ERASEBKGND后产生 2.WM_ ...
- java中怎么判断一个字符串中包含某个字符或字符串
public static void main(String[] args) { String str="ABC_001"; ){ System.out.println(" ...
- nginx的反向代理和负载均衡的区别是什么 - 开源中国社区
nginx的反向代理和负载均衡的区别是什么 - 开源中国社区 nginx的反向代理和负载均衡的区别是什么 #user nobody;worker_processes 1;#error_log ...