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控制)
网友评论