NSTimer介绍

1.创建NSTimer

常用方法有

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats;

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats;

- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats;

他们的区别:

scheduledTimerWithTimeInterval相比它的小伙伴们不仅仅是创建了NSTimer对象, 还把该对象加入到了当前的runloop中!

NSTimer只有被加入到runloop, 才会生效, 即NSTimer才会被真正执行

所以说, 如果你想使用timerWithTimeInterval或initWithFireDate的话, 需要使用NSRunloop的以下方法将NSTimer加入到runloop中

- (void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode

要让timer生效,必须保证该线程的runloop已启动,而且其运行的runloopmode也要匹配。

每一个线程都有它自己的runloop,程序的主线程会自动的使runloop生效,

但对于我们自己新建的线程,它的runloop是不会自己运行起来,当我们需要使用它的runloop时,就得自己启动。

runloop会运行在不同的mode, 简单来说有以下两种mode

NSDefaultRunLoopMode, 默认的mode

UITrackingRunLoopMode, 当处理UI滚动操作时的mode

主线程默认运行在NSDefaultRunLoopMode

在UI滚动时, runloop运行在UITrackingRunLoopMode

如果addTimerforMode是NSDefaultRunLoopMode,那么在UITrackingRunLoopMode下定时器就不运行

要想在这些场景下仍然及时触发NSTimer那应该怎么办呢?

应该使用NSRunLoopCommonModes,包含以上2个mode

[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];

例子

//创建一个定时器,

_timer=[NSTimer timerWithTimeInterval:10 target:self selector:@selector(changeTimeAtTimedisplay) userInfo:nil repeats:YES];



//手动加入到循环中

NSRunLoop *runloop=[NSRunLoop currentRunLoop];

[runloop addTimer:_timer forMode:NSRunLoopCommonModes];

当然这个定时器会自动启动,只不多过了十秒之后,才触发

fire的作用是提前触发定时器 ,如果执行

_timer.fireDate = CFAbsoluteTimeGetCurrent() + timeInterval;

那么会立即开始定时

2.销毁NSTimer

是否可以将NSTimer置nil, 而让iOS系统帮我们销毁NSTimer呢?

答案是: 不可以

原因:为了保证timer在未来触发指定事件时指定方法是有效的,将指定方法的接收者retain了一份。(重复性还是一次性的timer都是)

如果在VC在创建的NSTimer,VC会和timer相互强引用,VC的dealloc方法不会执行

[_timer invalidate]; // 可以打破相互强引用,真正销毁NSTimer对象

_timer = nil; // 对象置nil是一种规范和习惯

所以这段代码不能放在VC的dealloc方法中,可以放在VC的ViewWillDisappear方法中

3.NSTimer会是准时触发事件吗

答案是否定的。

NSTimer不是一个实时系统,因此不管是一次性的还是周期性的timer的实际触发事件的时间可能都会跟我们预想的会有出入。差距的大小跟当前我们程序的执行情况有关系,比如可能程序是多线程的,而你的timer只是添加在某一个线程的runloop的某一种指定的runloopmode中,由于多线程通常都是分时执行的,而且每次执行的mode也可能随着实际情况发生变化。

  假设你添加了一个timer指定2秒后触发某一个事件,但是签好那个时候当前线程在执行一个连续运算(例如大数据块的处理等),这个时候timer就会延迟到该连续运算执行完以后才会执行。重复性的timer遇到这种情况,如果延迟超过了一个周期,则会和后面的触发进行合并,即在一个周期内只会触发一次。但是不管该timer的触发时间延迟的有多离谱,他后面的timer的触发时间总是倍数于第一次添加timer的间隙。

4.BlocksKit中为NSTimer 写的分类

@implementation NSTimer (BlocksKit)

+ (instancetype)bk_scheduleTimerWithTimeInterval:(NSTimeInterval)seconds repeats:(BOOL)repeats usingBlock:(void (^)(NSTimer *timer))block

{

    NSTimer *timer = [self bk_timerWithTimeInterval:seconds repeats:repeats usingBlock:block];

    [NSRunLoop.currentRunLoop addTimer:timer forMode:NSDefaultRunLoopMode];

    return timer;

}

+ (instancetype)bk_timerWithTimeInterval:(NSTimeInterval)inSeconds repeats:(BOOL)repeats usingBlock:(void (^)(NSTimer *timer))block

{

    NSParameterAssert(block != nil);

    CFAbsoluteTime seconds = fmax(inSeconds, 0.0001);

    CFAbsoluteTime interval = repeats ? seconds : 0;

    CFAbsoluteTime fireDate = CFAbsoluteTimeGetCurrent() + seconds;

    return (__bridge_transfer NSTimer *)CFRunLoopTimerCreateWithHandler(NULL, fireDate, interval, 0, 0, (void(^)(CFRunLoopTimerRef))block);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值