美文网首页
GCD定时器

GCD定时器

作者: 哥只是个菜鸟 | 来源:发表于2021-05-19 11:34 被阅读0次
    目前这个定时器实现了APP中全局倒计时的功能,切换页面和前后台,包括修改系统时间都不受影响。
    • 1.修改系统时间导致的问题
    dispatch_walltime(NULL, 1);
    

    dispatch_walltime 是根据系统时钟的绝对时间,会受到系统时间的影响,如果修改系统时间,定时器会停止,所以我们使用dispatch_time

    dispatch_time(DISPATCH_TIME_NOW, 0), 1.0 * NSEC_PER_SEC, 0)
    
    • 2.切换前后台怎么倒计时继续
      开始切换前后台时分别直接获取的系统时间([NSDate date]),后面发现如果修改系统时间之后也没法用,最后获取手机的开机时间得到时间戳解决,还有参考了其他的获取开机时间的方法,但是试了好像不太准
    - (long)deviceLaunchTime {
        struct timespec ts;
        clock_gettime(CLOCK_MONOTONIC, &ts);
        return ts.tv_sec;
    }
    

    实现:

    dispatch_source_t _timer;
    long timeRemain;
    long currentTimes;
    
    + (instancetype)sharedInstance {
        static dispatch_once_t one;
        static OrderTimerModel *timerModel;
        dispatch_once(&one, ^{
            if (timerModel == nil) {
                timerModel = [[OrderTimerModel alloc] init];
            }
        });
        return timerModel;
    }
    
    - (void)countDownWithDay:(NSInteger)day
               withTotalTime:(long)totalTime
                    withHour:(NSInteger)hour
                  withMinute:(NSInteger)minute
                  withSecond:(NSInteger)second
               completeBlock:(void (^)(NSInteger totalTime, NSInteger day, NSInteger hour, NSInteger minute, NSInteger second))completeBlock {
        timeRemain = totalTime;
        [self addObserver];
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, 0), 1.0 * NSEC_PER_SEC, 0); //每秒执行
        dispatch_source_set_event_handler(_timer, ^{
            DDLogDebug(@"剩余时间%ld", timeRemain);
            if (timeRemain <= 0) {
                dispatch_source_cancel(_timer);
                completeBlock(timeRemain, 0, 0, 0, 0);
            } else {
                NSInteger s = 1;
                NSInteger m = s * 60;
                NSInteger h = m * 60;
                NSInteger d = h * 24;
                NSInteger day = timeRemain / d;                                        //天
                NSInteger hour = (timeRemain - day * d) / h;                           //时考虑天1天23小时59分钟59秒
                NSInteger minute = (timeRemain - day * d - hour * h) / m;              //分
                NSInteger second = (timeRemain - day * d - hour * h - minute * m) / s; //秒
                if (completeBlock) {
                    completeBlock(timeRemain, day, hour, minute, second);
                }
                if (timeRemain <= 0) {
                    dispatch_source_cancel(_timer);
                }
                timeRemain--;
            }
        });
        dispatch_resume(_timer);
    }
    
    - (void)cancelTimer {
        if (_timer) {
            dispatch_source_cancel(_timer);
            _timer = nil;
            [[NSNotificationCenter defaultCenter] removeObserver:self];
        }
    }
    
    - (void)addObserver {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppDidBackGround) name:UIApplicationDidEnterBackgroundNotification
                                                   object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppDidEnterForeground) name:UIApplicationWillEnterForegroundNotification
                                                   object:nil];
    }
    
    - (void)handleAppDidBackGround {
        currentTimes = [self deviceLaunchTime];
        dispatch_suspend(_timer);
    }
    
    - (void)handleAppDidEnterForeground {
        long foreInterval = [self deviceLaunchTime];
        if (currentTimes > 0) {
            int differ = (int)(foreInterval - currentTimes);
            timeRemain = (timeRemain >= 0) ? (timeRemain - differ) : timeRemain;
        }
        dispatch_resume(_timer);
    }
    
    - (long)deviceLaunchTime {
        struct timespec ts;
        clock_gettime(CLOCK_MONOTONIC, &ts);
        return ts.tv_sec;
    }
    
    - (void)dealloc {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    

    相关文章

      网友评论

          本文标题:GCD定时器

          本文链接:https://www.haomeiwen.com/subject/qlqpjltx.html