iOS 基础知识点小知识点好东西

iOS-倒计时实现的三种方式

2017-09-30  本文已影响209人  FlyElephant

倒计时实现由三种方式,一种是NSTimer,第二种是是CADisplayLink,第三中是通过GCD的方式来实现,效果图如下:

倒计时.gif

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
上一篇下一篇

猜你喜欢

热点阅读