定时器分为两种
第一种
//利用timer...创建一个定时器,这样创建的定时器必须加到RunLoop里才能正常执行
//经测试,这里就算是一个方法内的局部变量,定时器同样可以正常执行,如果定时器不能正常执行,可以检查是否是局部变量销毁导致的,可以用一个强指针引用就可以
NSTimer *timer = [NSTimer timerWithTimeInterval:5.0target:selfselector:@selector(show) userInfo:nilrepeats:YES];
//用于多线程,由于系统现在只有一个线程,所以一次只能执行一件事,那么执行别的事件的时候,就会阻塞定时器,这时候,需要将定时器加到主线程,采用通用模式(通用模式里边包括两种基本RUnLoop模式,因此,在不同操作下都可以执行定时器),
//系统会将1s等分成若干份,循环执行这些事件,那么就造成同时执行的假象
//加入RunLoop内的定时器,会在一个间隔时间后开始执行,例如5.0秒,就是触发,5秒之后开始执行
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
//定时器立即执行,通俗的讲就是触发后,定时器立即执行一次,一个间隔时间后RunLoop内的开始起作用(可以这样认为)
[timer fire];
第二种
//这种方式,创建后可以在一个时间间隔后直接开始运行,而不用添加到RunLoop,并且timer是方法内的局部变量的时候,定时器依旧可以正常执行
//这种方式不用添加到RunLoop是因为scheduled的初始化方法将以默认mode直接添加到当前的runloop中.这就出现一个问题,当有滑动操作时,RunLoop的Mode就会变为
*UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode的影响
这时候在默认Mode里的定时器就暂停执行,等Mode转换回默认Mode的时候继续执行,
为了解决这种问题,可以将scheduled这种方式创建的timer也添加到通用模式下Common,这样就可以在两种Mode下都正常执行
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0target:selfselector:@selector(show) userInfo:nilrepeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
//这个方法还是让定时器立刻执行
[timer fire];
- (void)invalidate;
这个是唯一一个可以将计时器从runloop中移出的方法。
//删除定时器
- (void)stopTimer
{
[self.timer invalidate];
self.timer =nil;
}
GCD定时器
GCD定时器非常准确,不受其他操作的影响
//获取一个全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0,0);
//GCD定时器
//1、创建一个GCD定时器,需要传入一个队列
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0,0, queue);
//这里必须用一个强指针指向,如果没有,那么timer就是一个局部变量,运行到方法结束,timer就没有了,等调用定时器方法的时候,timer已经不存在了,定时器无法正常开启
self.timer = timer;
//设置定时器的开始时间,间隔时间,和精准度
//GCD的单位是纳秒,内部进行了转换,10的9次方
//精准度:一般为0,如果对定时操作要求不精确,只要在一段时间内执行就可以,那么可以把精准度设置的大一点,例如10,这样会提高程序性能
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW,2.0* NSEC_PER_SEC,0* NSEC_PER_SEC);
//设置定时器要调用的方法
dispatch_source_set_event_handler(timer, ^{
NSLog(@"GCD定时器正在运行");
});
//启动定时器
dispatch_resume(timer);