一、NSTimer定时器不准:
如果在子线程中创建Timer,那么当我们add到RunLoop的时候有NSDefaultRunLoopMode和NSRunLoopCommonModes两种模式可以选择
- 这里不像主线程,子线程需要创建loop并且run起来,不然是不会连续跑任务的
- 不准的原因在于,当我们在NSDefaultRunLoopMode模式下跑的时候,我们滚动例如TableView的时候切换到
- TrackingMode,loop会退出当前mode,重新进入指定的mode,如果NSTimer不是加到NSRunLoopCommonModes
- 那么任务跑起来一直在切换,肯定会不准
NSTimer *timer= [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
二、GCD创建定时器
GCD创建的定时器不受RunLoop中Modes影响;
注意
:将定时器写成属性,是因为内存管理的原因,使用了dispatch_source_create方法,这种方法GCD是不会帮你管理内存的。
@property (nonatomic,strong) dispatch_source_t timer;
/**
创建一个定时器
参数1:代表创建一个定时器
参数4:队列
这里的强引用是因为,当我定时器延时几秒调用的时候,局部变量就死了,我们需要强引用起来
*/
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
/**
设置定时器
参数1:定时器对象
参数2:GCD dispatch_time_t 里面的都是纳秒 创建一个距离现在多少秒开启的任务
参数3:间隔多少秒调用一次
问题
:DISPATCH_TIME_NOW用这个,开始倒计时那1-2s会跑得有点快
dispatch_source_set_timer(self.timer,DISPATCH_TIME_NOW,1.0*NSEC_PER_SEC, 0);
*/
dispatch_source_set_timer(self.timer, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), (uint64_t)(1.0 * NSEC_PER_SEC), 0); // 设置回调
//执行这个以后,会立即执行一次
dispatch_source_set_event_handler(self.timer, ^{
});
dispatch_resume(self.timer);
}
参数详解:
dispatch_source_create(dispatch_source_type_t type,
uintptr_t handle,
unsigned long mask,
dispatch_queue_t _Nullable queue)
第一个参数:dispatch_source_type_t type为设置GCD源方法的类型,前面已经列举过了。
第二个参数:uintptr_t handle Apple的API介绍说,暂时没有使用,传0即可。
第三个参数:unsigned long mask Apple的API介绍说,使用DISPATCH_TIMER_STRICT,会引起电量消耗加剧,毕竟要求精确时间,所以一般传0即可,视业务情况而定。
第四个参数:dispatch_queue_t _Nullable queue 队列,将定时器事件处理的Block提交到哪个队列之上。可以传Null,默认为全局队列。
dispatch_source_set_timer(dispatch_source_t source,
dispatch_time_t start,
uint64_t interval,
uint64_t leeway);
第一个参数:dispatch_source_t source......不用说了
第二个参数:dispatch_time_t start, 定时器开始时间,类型为 dispatch_time_t,其API的abstract标明可参照dispatch_time()
和dispatch_walltime()
,同为设置时间,但是后者为“钟表”
时间,相对比较准确,所以选择使用后者。dispatch_walltime(const struct timespec *_Nullable when, int64_t delta),参数when可以为Null,默认为获取当前时间,参数delta为增量,即获取当前时间的基础上,增加X秒的时间为开始计时时间,此处传0即可。
第三个参数:uint64_t interval,定时器间隔时长,由业务需求而定。
第四个参数:uint64_t leeway, 允许误差,此处传0即可。