1.NSTimer
创建NSTimer
//常用方法
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
//常用方法
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep
- scheduledTimerWithTimeInterval 方法相比timerWithTimeInterval,不仅初始化了一个timer对象,同时还将该对象放入到当前的Runloop中,而后者需要手动将timer放入runloop。最重要的是NSTimer只有放到runloop才会生效。(runloop后面会专门写一下)。
-(void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode
- timer定时器并不是一个精确运行的,精确运行需要用GCDtimer
- 正常情况下tableView等滚动视图添加timer后,视图滚动后
RunLoop会将mode切换成TrackingRunLoopMode 不会调用timer
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateUI) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
//NSRunLoopCommonModes的意思为,定时器可以运行在标记为common modes模式下。
//具体包括两种: kCFRunloopDefaultMode 和 UITrackingRunloopMode。
[timer fire];
暂停/启动NSTimer
//启动,常用方法创建的直接就启动了
[self.timer setFireDate:[NSDate distantPast]];
//暂停
[self.timer setFireDate:[NSDate distantFuture]];
释放NSTimer
释放写在viewWillDisappear!!!!!
[self.timer invalidate];//将timer停止并移出runloop
self.timer = nil;
NSTimer在ARC下
初始化后放到runloop后,除了ViewController外,iOS系统也强引用NSTimer对象。
将timer对象置nil后,会解除VC对timer的中引用。但iOS系统依然对NSTimer和VC存在强引用关系。(因为并未解除系统对timer的强引用,并且系统为了实现NSTimer而对VC继续保持引用)。所以先对timer 执行invalidate(解系统对timer的强引用),再置nil(解除VC对timer引用)。
由于系统和VC对timer的双重引用,导致dealloc 方法无法执行,所以理想的方法是释放代码写在viewWillDisappear方法中。
2.GCD
dispatch source是一个监视某些类型事件的对象。
当这些事件发生时,它自动将一个block放入一个dispatch queue的执行例程中。
/**
* 创建dispatch源
*
* @param DISPATCH_SOURCE_TYPE_TIMER 事件源的类型
* @param 0 <#0 description#>
* @param 0 <#0 description#>
* @param dispatch_get_main_queue 在哪个线程上执行
*
* @return dispatch_source_t
*/
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
/**
* @param start 控制计时器第一次触发的时刻
* @param interval 每隔多长时间执行一次
* @param leeway 误差值,0表示最小误差,值越小性能消耗越大
*/
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
//事件处理的回调
dispatch_source_set_event_handler(timer, ^{
});
// Dispatch source启动时默认状态是挂起的,创建完毕之后得主动恢复,
//否则事件不会被传递,也不会被执行
dispatch_resume(timer);
//取消定时器
dispatch_cancel(timer);
3.CADisplayLink
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(disPlay)];
//与NSTimer不同, 需要手动添加到RunLoop中, 如果添加的模式是NSDefaultRunLoopMode, 则scrollview滚动时, 会阻碍定时器的执行。
//如果是NSRunLoopCommonModes, 则不会阻碍。
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
//设置刷新频率, 默认是每秒60帧, 如果设置成60就每秒执行一次
//但是实际测试却发现,设置60是2秒执行一次, 设置成30才是每秒执行一次。但精度依然比NSTimer高
displayLink.frameInterval = 60;