NSTimer使用机及其注意事项(一)

来源:互联网 发布:知乎日报 正装 编辑:程序博客网 时间:2024/06/12 13:06

NSTimer使用机及其注意事项(一)
主要3点,本文主要前2项,下篇第3项。
一.一般使用事项
二.与RunLoop的关系
三.repeats释放不掉的问题

一. 一般使用事项
1.初始化方式

 scheduledTimerWithTimeInterval:invocation:repeats:  scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:  timerWithTimeInterval:invocation:repeats:  timerWithTimeInterval:target:selector:userInfo:repeats:  initWithFireDate:interval:target:selector:userInfo:repeats: 

2.scheduled的两个方法将默认的把timer对象加入到当前的RunLoop中(Timer与RunLoop的关系下面说,如果Timer不加入到某一RunLoop中,将不会触发他的功能);
3.timerWithTimeInterval:的两个方法不会把timer对象加入到RunLoop中;
4.iOS10之后加入了三个block方法,block的方法就直接在block里面写延时后要执行的代码就可以了;
5.几个属性,fire立刻触发事件,fireDate设置触发timeInterval,tolerance这是7.0之后新增的一个属性,因为NSTimer并不完全精准,通过这个值设置误差范围。invalidate停止触发事件并请求从run loop里remove掉;
6.其他事项,timeInterval参数设置的时间如果小于等于0的话,系统默认取0.1ms(没什么用,人眼根本察觉不出来这么短的时间);
7.如果timer的repeats是NO的话,那么触发一次之后,系统自动调用invalidate(A non-repeating timer fires once and then invalidates itself automatically, thereby preventing the timer from firing again);

二.与RunLoop的关系
NSTimer对象如果不加入一个RunLoop的话,那么他是一个无效的timer(PS:scheduledTimerWithTimeInterval初始化的timer对象系统默认加入到当前的RunLoop中);
如下图,我们注释掉加入run loop的代码,那么timer将不会触发对应的事件注释掉RunLoop
所以我们同时也能回答了下个问题,NSTimer会是准时触发事件吗, 答案是否定的,而且有时候你会发现实际的触发时间跟你想象的差距还比较大。NSTimer不是一个实时系统,因此不管是一次性的还是周期性的timer的实际触发事件的时间可能都会跟我们预想的会有出入。差距的大小跟当前我们程序的执行情况有关系,比如可能程序是多线程的,而你的timer只是添加在某一个线程的runloop的某一种指定的runloopmode中,由于多线程通常都是分时执行的,而且每次执行的mode也可能随着实际情况发生变化。
比如,我们打算让timer对象在1s后触发某一事件,但是刚好那个时间当前的线程在处理一个耗时操作,比如数据块的处理,这个时候timer就会延迟到该连续运算执行完以后才会执行。重复性的timer遇到这种情况,如果延迟超过了一个周期,则会和后面的触发进行合并,即在一个周期内只会触发一次。但是不管该timer的触发时间延迟的有多离谱,他后面的timer的触发时间总是倍数于第一次添加timer的间隙。

- (void)viewDidLoad {    [super viewDidLoad];    self.view.backgroundColor = [UIColor grayColor];    _timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerFire:) userInfo:nil repeats:YES];    [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];    [self performSelector:@selector(simulateBusy) withObject:nil afterDelay:3];}- (void)simulateBusy{    NSLog(@"start simulate busy!");    NSUInteger caculateCount = 1000000000;    CGFloat uselessValue = 0;    for (NSUInteger i = 0; i < caculateCount; ++i) {        uselessValue = i / 0.3333;    }    NSLog(@"finish simulate busy!");}-(void)timerFire:(id)userinfo {    NSLog(@"Fire");}

这里写图片描述
我们看到大计算期间,timer没有触发事件,并且在计算完成后,03.404立刻触发了timer一次,然后在03.642在触发一次,表明间隙要变成原来的整数倍,所以在03间触发了2次。

PS.注意加入到RunLoop的mode方式,我们刚才的NSTimer默认添加在NSDefaultRunLoopMode上,而UIScrollView在滑动的时候,RunLoop会自动切换到 UITrackingRunLoopMode,NSTimer并没有添加到这个RunLoop模式上,自然也是不会启动的。所以,如果我们想要NSTimer在UIScrollView滑动的时候也会启动的话,只要将NSTimer添加NSRunLoopCommonModes上即可。NSRunLoopCommonModes是RunLoop模式的集合。

0 0
原创粉丝点击