使用NSTimer时遇到的问题归类

1. NSRunLoopCommonModes和Timer

  当使用NSTimer的scheduledTimerWithTimeInterval方法时。事实上此时Timer会被加入到当前线程的Run Loop中,且模式是默认的NSDefaultRunLoopMode。而如果当前线程就是主线程,也就是UI线程时,某些UI事件,比如UIScrollView的拖动操作,会将Run Loop切换成NSEventTrackingRunLoopMode模式,在这个过程中,默认的NSDefaultRunLoopMode模式中注册的事件是不会被执行的。也就是说,此时使用scheduledTimerWithTimeInterval添加到Run Loop中的Timer就不会执行。

  所以为了设置一个不被UI干扰的Timer,我们需要手动创建一个Timer,然后使用NSRunLoop的addTimer:forMode:方法来把Timer按照指定模式加入到Run Loop中。这里使用的模式是:NSRunLoopCommonModes,这个模式等效于NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的结合。(参考Apple文档)

参考代码:

- (void)viewDidLoad{

[super viewDidLoad];

NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timer_callback)userInfo:nil repeats:YES];

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

}

总结:NSTimer默认使用NSDefaultRunLoopMode模式,这种模式的有限级较低,会被tableview的滑动调用的NSEventTrackingRunLoopMode模式阻碍,导致NSTimer会被等待执行。常规处理方式未[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes],把timer加入到forMode:NSRunLoopCommonModes模式下,这种模式可以和NSEventTrackingRunLoopMode同时执行


2.NSTimer的释放 

首先写一个错误的写法,怎么定义这是个错误呢,就是非常规写法.

-(void)dealloc {

[_timer invalidate];

NSLog(@"%@ dealloc", NSStringFromClass([self class]));

}

timer创建

_timer = [NSTimer scheduledTimerWithTimeInterval:3.0f

target:self

selector:@selector(timerFire:)

userInfo:nil

repeats:YES];


把target设置为self,就是在NSRunloop里面强引用了self,也就是说如果这个timer不释放,那么当前self永远不会调用dealloc,通常做法就是在viewwilldiasppera或者 你自己写的一些释放方法里面调用.

题外话:VC的创建是先初始化VC,再初始化VC上的view的父类,再初始化view。释放的时候顺序相反,程序调用dealloc的时候会这么写

-(void)dealloc {

}

看着是个空函数,其实上执行了很多代码,它存在的意思就是告诉你,它要开始销毁了,他会先把VC上的view全部释放掉,然后再释放掉自己,这个空函数执行完的时候,self被释放完了(当前这个过程是由ARC控制)

你可能感兴趣的:(使用NSTimer时遇到的问题归类)