倒计时实现由三种方式,一种是NSTimer,第二种是是CADisplayLink,第三种是通过GCD的方式来实现,效果图如下:
NSTimer
NSTimer作为倒计时有两个重要的执行方式:
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
倒计时代码:
- (void)setupTimer {
self.topLabel.text = [NSString stringWithFormat:@"%ld",topCount];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTopLabel) userInfo:nil repeats:YES];
}
- (void)updateTopLabel {
topCount -= 1;
self.topLabel.text = [NSString stringWithFormat:@"%ld",topCount];
if (topCount == 0) {
[self.timer invalidate];
}
}
CADisplayLink
CADisplayLink是一个能够和屏幕刷新率相同的频率将内容画到屏幕上的定时器.我们在应用中创建一个新的 CADisplayLink 对象,把它添加到一个runloop中,并给它提供一个 target 和selector 在屏幕刷新的时候调用.
初始化CADisplayLink:
self.midLabel.text = @"60";
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateMidLabel)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
CADisplayLink每秒执行60次,除以60根据余数是否是0来判断是否过了一秒:
- (void)updateMidLabel {
midCount += 1;
if (midCount % 60 == 0) {
NSInteger result = 60 - midCount / 60;
self.midLabel.text = [NSString stringWithFormat:@"%ld",result];
if (result == 0) {
[self.displayLink invalidate];
}
}
}
控制器即将消失的时候销毁Timer和DisplayLink,避免控制器不释放:
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
if ([self.timer isValid]) {
[self.timer invalidate];
}
[self.displayLink invalidate];
}
GCD
GCD实现倒计时的方式,相对其他两种复杂一点,dispatch_source_set_timer设置倒计时,dispatch_source_set_event_handler设置倒计时执行的任务.
- (void)setupGCD {
self.bottomLabel.text = @"60";
__block NSInteger bottomCount = 61;
//获取全局队列
dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建一个定时器,并将定时器的任务交给全局队列执行
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, global);
// 设置触发的间隔时间 1.0秒执行一次 0秒误差
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
__weak typeof(self)weakSelf = self;
dispatch_source_set_event_handler(timer, ^{
if (bottomCount <= 0) {
//关闭定时器
dispatch_source_cancel(timer);
}else {
bottomCount -= 1;
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.bottomLabel.text = [NSString stringWithFormat:@"%ld",bottomCount];
});
}
});
dispatch_resume(timer);
}
UI初始化:
@interface DetailViewController () {
NSInteger topCount;
NSInteger midCount;
}
@property (weak, nonatomic) IBOutlet UILabel *topLabel;
@property (weak, nonatomic) IBOutlet UILabel *midLabel;
@property (weak, nonatomic) IBOutlet UILabel *bottomLabel;
@property (strong, nonatomic) NSTimer *timer;
@property (strong, nonatomic) CADisplayLink *displayLink;
@end