Runloop Timer為什么不準(zhǔn)?
1:Runloop Timer底層使用的timer精度不高;
2:與Runloop底層的調(diào)用機(jī)制有關(guān)系。
情況產(chǎn)生:
1、NSTimer被添加在mainRunLoop中,模式是NSDefaultRunLoopMode,mainRunLoop負(fù)責(zé)所有主線程事件,例如UI界面的操作,復(fù)雜的運(yùn)算使當(dāng)前RunLoop持續(xù)的時(shí)間超過了定時(shí)器的間隔時(shí)間,那么下一次定時(shí)就被延后,這樣就會(huì)造成timer的阻塞。
2:模式的切換,當(dāng)創(chuàng)建的timer被加入到NSDefaultRunLoopMode時(shí),此時(shí)如果有滑動(dòng)UIScrollView的操作,runLoop 的mode會(huì)切換為TrackingRunLoopMode,這是timer會(huì)停止回調(diào)。
解決:
1:在主線程中創(chuàng)建timer,timer添加到當(dāng)前Runloop并設(shè)置RunloopType為NSRunLoopCommonModes。
2: 在子線程中創(chuàng)建timer,GCD操作:dispatch_source_create,創(chuàng)建定時(shí)器,dispatch_source_set_timer :設(shè)置定時(shí)器。dispatch_resume:?jiǎn)?dòng)。
3:CADisplayLink(頻率能達(dá)到屏幕刷新率的定時(shí)器類):displayLinkWithTarget,addToRunLoop
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
/* 定時(shí)器 */
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic , strong ) dispatch_source_t atimer;
@end
#import "ViewController.h"
@interface ViewController ()
{
UILabel *_label;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
_label.center = self.view.center;
_label.textColor = [UIColor blackColor];
_label.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:_label];
//正常用法,作用于主線程的runloop,主線程要處理UI會(huì)影響精準(zhǔn)度,Scollview滑動(dòng)時(shí)mode切換為TrackingRunLoopMode,NSTimer會(huì)停止回調(diào)。
[self normalUser];
//1、在主線程中切換runloopMode
[self mainloopchangemode];
//2、異步線程創(chuàng)建NSTimer
[self asyCreateTimer];
//3、使用CADisplayLink
[self userCADisplyLink];
}
int i = 0;
-(void)normalUser{
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(addtime) userInfo:nil repeats:YES];
}
-(void)mainloopchangemode{
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
-(void)asyCreateTimer{
self.atimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(self.atimer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 1 * NSEC_PER_SEC );
dispatch_source_set_event_handler(self.atimer, ^{
self->_label.text = [NSString stringWithFormat:@"當(dāng)前:%d",i];
i++;
});
dispatch_resume(self.atimer);
}
-(void)userCADisplyLink{
//較為精準(zhǔn),與屏幕刷新幀率同步,多用戶視圖渲染或繪圖
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(addtime)];
[link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
-(void)addtime{
_label.text = [NSString stringWithFormat:@"當(dāng)前:%d",i];
i++;
}
@end