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的更多相关文章

  1. Java并发编程:Timer和TimerTask(转载)

    Java并发编程:Timer和TimerTask(转载) 下面内容转载自: http://blog.csdn.net/xieyuooo/article/details/8607220 其实就Timer ...

  2. Java并发编程:Timer和TimerTask

    Java并发编程:Timer和TimerTask 下面内容转载自: http://blog.csdn.net/xieyuooo/article/details/8607220 其实就Timer来讲就是 ...

  3. 16、Java并发编程:Timer和TimerTask

    Java并发编程:Timer和TimerTask(转载) 下面内容转载自: http://blog.csdn.net/xieyuooo/article/details/8607220 其实就Timer ...

  4. Java编程Tips

    原文: Java编程中"为了性能"尽量要做到的一些地方 作者: javatgo 最近的机器内存又爆满了,除了新增机器内存外,还应该好好review一下我们的代码,有很多代码编写过于 ...

  5. [C++]高效C/C ++编程tips

    Effective C++ 视C++ 为一个语言联邦(C.Object-Oriented C++.Template C++.STL) 宁可以编译器替换预处理器(尽量以const.enum.inline ...

  6. 编程Tips集锦

    以下是自己编程的一些小贴士,记录,总结提高自己. 1.python中集合类型的查找,尽量用dict or set类型. dict和set类型,在python内部的实现都是使用hash映射,查找的时间复 ...

  7. 前端编程tips

    1.ts less 网上搜视频教程,不用太复杂的,短短几分钟视频基本就对其入门了,比自己搜官网学习更方便. 常用的ts技术:let name:string="";  let obj ...

  8. 编程Tips

    三元运算符 Vb中的iif(expr,truepart,falsepart)和C#中的expr?truepart:falsepart. 无论expr的结果是true还是false,true/false ...

  9. stm8编程tips(stvd)

    编译完成时显示程序占用的flash和ram大小 将附件压缩包中的mapinfo.exe解压到stvd的安装路径\stvd中 在工程上点右键选settings 右侧的选项卡选择Linker,将categ ...

  10. C#中Timer使用及解决重入问题

    C#中Timer使用及解决重入问题 ★介绍 首先简单介绍一下timer,这里所说的timer是指的System.Timers.timer,顾名思义,就是可以在指定的间隔是引发事件.官方介绍在这里,摘抄 ...

随机推荐

  1. dos2unix与unix2dos之学习记录

    1. unix2dos与dos2unix这两个tool是用来干什么的? 这首先应该要说明一下背景知识: unix类操作系统下,换行字符是\n: 而早期的dos操作系统,其换行字符是由\r\n组成. 所 ...

  2. LWP::UserAgent - Web user agent class Web 用户agent 类:

    LWPUserAgent: LWP::UserAgent - Web user agent class Web 用户agent 类: 概述: require LWP::UserAgent; my $u ...

  3. 【剑指offer】Q38:数字在数组中出现的次数

    与折半查找是同一个模式,不同的是,在这里不在查找某个确定的值,而是查找确定值所在的上下边界. def getBounder(data, k, start, end, low_bound = False ...

  4. jQuery Easy UI Resizable(调整大小)组件

    Resizable(调整大小)组件,easyui基础组件之中的一个.调整大小就是能够对元素能够拖着调整大小,这个组件不依赖于其它组件,使用比較简单,相关的属性.事件都 在样例中介绍了. 演示样例: & ...

  5. linux脚本:shell, 判断输入参数的个数(命令行)

    if [ $# != 3 ] ; thenecho "USAGE: $0 from to"echo " e.g.: $0 ~/oucaijun/from ~/oucaij ...

  6. Qt MinGW 使用联合编译IncrediBuild

    联合编译工具IncrediBuild提供了接口,以使得可以使用网格来处理各种任务,而不仅仅是VS的联合编译,文档地址:http://www.incredibuild.com/webhelp/xge_h ...

  7. 拷贝构造函数和const成员函数

    实验原因 说明如何使用const描述保护类数据不会意外修改. 编译环境 vc6sp6 + win7x64 工程下载 copyConstruction_constMemberFunction.zip   ...

  8. PHP环境部署问题集合

    Forbidden You don't have permission to access /phpmyadmin/ on this server. 安装wamp 后访问 http://localho ...

  9. URAL 1018 (金典树形DP)

    连接:1018. Binary Apple Tree Time limit: 1.0 second Memory limit: 64 MB Let's imagine how apple tree l ...

  10. Linux/ubuntu下的boost库安装

    我一直都没有写博客的习惯,最近正好在研究linux下的开发(目前也只是粗粗的研究),且用到了boost库,就乘此机会写点什么,最起码记录一下我在安装boost的一些步骤,主要给和我一样的linux开发 ...