您的位置:首页 > 移动开发 > IOS开发

iOS倒计时设计思路和一个系统时间的坑

2017-05-08 18:32 288 查看

个人知识点记录,仅供参考

1.用GCD定时器更准确

2.当前时间要用服务器时间

3.如何考虑手机锁屏线程休眠

4.如何做到tableViewCell里面放倒计时

5.到期时间不变,当前时间在变,主要操作的是这个差值

Demo分析

1.创建GCD定时器 Demo用NSDate来模拟服务器当前时间

@property (nonatomic,strong) dispatch_source_t timer;
- (void)refreshDataForCountDown{
if (!self.timer) {
__weak typeof(self) weakSelf = self;
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1.0f * NSEC_PER_SEC, 0.0f * NSEC_PER_SEC);
dispatch_source_set_event_handler(self.timer, ^{

@autoreleasepool {
NSLog(@"定期器跑起来了。。。");
NSTimeInterval timerTop = ([[NSProcessInfo processInfo] systemUptime] - weakSelf.appStartTimeTop);
NSTimeInterval timerBottom = ([weakSelf uptime] - weakSelf.appStartTimeBottom);

weakSelf.topLabel.text = [weakSelf.formatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:weakSelf.serverTimeTop + timerTop]];
weakSelf.bottomLabel.text = [weakSelf.formatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:weakSelf.serverTimeBottom + timerBottom]];

}
});
dispatch_resume(self.timer);
}
}


2.获取当前设备系统/进程的时间

进程时间

[[NSProcessInfo processInfo] systemUptime]


系统内核时间(这里有介绍该方法

int sysctl(int *, u_int, void *, size_t *, void *, size_t);


这里先针对Demo分析下,这两个获取当前系统时间的方法,主要用他们来给服务器时间补差值,比如说你获取到服务器时间之后,啥都没做,过了几秒钟,你肯定需要记录系统时间,把服务器时间加上这个差值,就是时时模拟出来的服务器时间,OK这个没问题了,那么问题来了,当你手机开着的时候,没问题的,你看不出来的,但是你锁屏你试试,等几分钟来看看,你会发现NSProcessInfo对应下的时间慢了。。。。。

直接看这个吧,这里有详细讨论



但是有个注意点,我也被恶心了一下午,测试的时候记得把你的数据线拔了,不然你锁屏的时候进程也不会休眠的。。

看下效果,记住你拔掉你的数据线,锁屏,等几分钟来看看,两个时间就不准了



总结:NSProcessInfo是不准确的,我们要用内核的系统时间,这样才不受线程休眠的影响,你无论什么状态下获取到都是正确的时间差,加上你请求到的服务器时间,就是完美的当前时间

- (NSTimeInterval)uptime
{
struct timeval boottime;
int mib[2] = {CTL_KERN, KERN_BOOTTIME};
size_t size = sizeof(boottime);

struct timeval now;
struct timezone tz;
gettimeofday(&now, &tz);

double uptime = -1;

if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0)
{
uptime = now.tv_sec - boottime.tv_sec;
uptime += (double)(now.tv_usec - boottime.tv_usec) / 1000000.0;
}
return uptime;
}


3.重新刷新一次时间就恢复了



- (IBAction)refreshTime:(id)sender {
self.serverTimeTop = [[NSDate date] timeIntervalSince1970];
self.serverTimeBottom = [[NSDate date] timeIntervalSince1970];

self.appStartTimeTop = [[NSProcessInfo processInfo] systemUptime];
self.appStartTimeBottom = [self uptime];
}


如果你不刷新,你获取到的systemUptime已经滞后了(线程休眠导致的),那么你算出来的差值自然已经滞后了,但是内核的时间是肯定准确的,如果你刷新一次,又同步了两个时间,又恢复了,这个Demo只是验证NSProcessInfo不能用来进行获取进程行走的时间,稍微分析下倒计时逻辑

倒计时思路 —>>有问题的话可以留言交流

1.核心思想是只操作数据源,KVO的方式进行UI倒计时

2.通过请求数据获取到一个到期时间,然后根据系统时间算于出当前时间的差值

3.在适当的地方开启定时器修改数据源的差值字段,cell进行监听刷新UI

4.手机锁屏的时候切换到后台,再次进来你要再次根据当前服务器时间刷新这个差值,重新进行当前的倒计时,如果不刷新,线程休眠,你的差值是不变的,而系统时间在走,因此都要跟着变,就在App进入前台的时候重新给数据源的差值进行计算赋值(这里如何保证系统时间准确,记得用sysctl内核方法去获取)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐