有关定时器NSTimer使用

最近闲的没事看了一下定时器,那么就写下来,介绍一下定时器。

首先,说说定时器的应用场景:

  1当我们需要反复间隔一段时间做的事情.

  2当我们需要延时执行一些操作时候。(当然我们也可以使用

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;

以上两种方式 都是类似原理;

我推荐使用 dispatch after来做,可以确保多线程下依然有效。(至于dispatch怎么做repeat多次操作,可以用递归实现。下面我回贴一下代码)


- (void)doSomething{
    __weak yourController *weakSelf = self;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                if (某条件成立) {
                    [weakSelf doSomething];
                }
}



当然你如果需要了解timer可以去看看官方文档:https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/index.html#//apple_ref/doc/uid/TP40003747


以下是创建一个定时器方法,我会分别介绍,在介绍定时器使用之前,我会介绍一下定时器是如何工作的。定时器是基于runloop的,你创建的定时器必须是添加到runloop上才可以工作,你不必对他强持有,因为runloop已经做了这个事情。当合适的时候,就会触发,你也可以调用fire去立刻触发他.当然由于是基于runloop管理的,那么就会存在误差,比如我们在回调中处理一些耗时操作,活着是在不同的runloop mode模式下也会有影响。!那么你会问,万一控制器销毁了,timer依然调用控制器的方法,不就会造成crash。苹果也考虑到了这点,当我们新建一个timer时候,timer都会去对targer对象持有一份,以保证timer还活着的时候,控制器不会被销毁。

Creating a Timer

Information About a Timer



NSTimer的保留环问题。
1)当我们使用使用NSTimer,且repats设置为YES时候,如果不释放NSTimer是会造成内存泄露的。你肯定会说,我去执行 invalidate方法不就解决了。
     但是有些时候 你是想控制器销毁时候去销毁定时器的,你肯定会说,那我们在dealloc里执行 invalidate不就好了。好了 如果你说这句话,说明你没有理解NSTimer的工作     了。你可以回头看看我写的“ 当我们新建一个timer时候,timer都会去对target对象持有一份,以保证timer还活着的时候,控制器不会被销毁”这句话。
    也就是说 只要timer活着,控制器就不会被销毁,dealloc也就不会被执行。所以在dealloc里调用indalidate方法是没有效果的。我们暂且把这种现象称为NSTimer的保留环问       题。
2)那我们如何去解决这个问题呢,当然就是想要timer不要对控制器的方法强持有。
解决的方法是在NSTimer 的基础上,建一个分类(Category) 并实现一个类方法,这里我们叫做:
+(NSTimer *)kscheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void (^)())block repeats:(BOOL)repeats;

#import <Foundation/Foundation.h>
//接口部分
@interface NSTimer (CLBlockSupport)
+(NSTimer *)kscheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats;
@end
//实现部分
@implementation NSTimer (CLBlockSupport)
+(NSTimer *)kscheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void (^)())block repeats:(BOOL)repeats
{
    return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(clblockInvoke:)userInfo:[block copy]repeats:repeats];
}
+(void)clblockInvoke:(NSTimer*)timer
{
   void(^block)()=timer.userInfo;
   if (block) {
        block();
    }
}
解释一下:这个办法如何能解决"保留环"的问题呢?通过代码可以看到,这段代码将计时器所应执行的任务封装成块,在调用计时器函数时,把他作为userinfo参数传进去.该参数可用来存放"万能值",只要计时器还有效,就会一直保留他.传入参数时要通过copy方法将block拷贝到"堆"上,否则等到稍后要执行它的时候,该块可能已经无效了.计时器现在的target是NSTimer类对象,这是一个单例,因此计时器是否会保留它,已经无所谓了.此处依然有保留环,但是因为类对象无须回收,所以不用担心.


注意:创建timer的时候,先定义一个弱(weak)引用,令其指向self,然后使Block捕获这个引用,而不是直接捕获普通的self变量,也就是说,self不会为计时器所保留.当Block开始执行时,立刻生成强(strong)引用,以保证实例在执行期间持续存活.下面是一个使用这个方法的例子:
__unsafe_unretained ClassA * weakView =self
timer = [NSTimerclscheduledTimerWithTimeInterval:1.0block:^{
   ClassA * strongView = weakView;
   [strongViewstartGo];
}repeats:YES];

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值