倒計(jì)時(shí)實(shí)現(xiàn)由三種方式,一種是NSTimer韵吨,第二種是是CADisplayLink匿垄,第三種是通過(guò)GCD的方式來(lái)實(shí)現(xiàn),效果圖如下:
NSTimer
NSTimer作為倒計(jì)時(shí)有兩個(gè)重要的執(zhí)行方式:
+ (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;
倒計(jì)時(shí)代碼:
- (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是一個(gè)能夠和屏幕刷新率相同的頻率將內(nèi)容畫到屏幕上的定時(shí)器.我們?cè)趹?yīng)用中創(chuàng)建一個(gè)新的 CADisplayLink 對(duì)象归粉,把它添加到一個(gè)runloop中椿疗,并給它提供一個(gè) target 和selector 在屏幕刷新的時(shí)候調(diào)用.
初始化CADisplayLink:
self.midLabel.text = @"60";
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateMidLabel)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
CADisplayLink每秒執(zhí)行60次,除以60根據(jù)余數(shù)是否是0來(lái)判斷是否過(guò)了一秒:
- (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];
}
}
}
控制器即將消失的時(shí)候銷毀Timer和DisplayLink糠悼,避免控制器不釋放:
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
if ([self.timer isValid]) {
[self.timer invalidate];
}
[self.displayLink invalidate];
}
GCD
GCD實(shí)現(xiàn)倒計(jì)時(shí)的方式届榄,相對(duì)其他兩種復(fù)雜一點(diǎn),dispatch_source_set_timer設(shè)置倒計(jì)時(shí)倔喂,dispatch_source_set_event_handler設(shè)置倒計(jì)時(shí)執(zhí)行的任務(wù).
- (void)setupGCD {
self.bottomLabel.text = @"60";
__block NSInteger bottomCount = 61;
//獲取全局隊(duì)列
dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//創(chuàng)建一個(gè)定時(shí)器铝条,并將定時(shí)器的任務(wù)交給全局隊(duì)列執(zhí)行
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, global);
// 設(shè)置觸發(fā)的間隔時(shí)間 1.0秒執(zhí)行一次 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) {
//關(guān)閉定時(shí)器
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