天文台iOS 时间校准解决方案

By admin in 天文台 on 2018年10月25日

背景

在 iOS
开发中,凡是用到网时的,都如考虑一个问题:对时。有些工作是不必对时,或可以以用户时间也本的,比如卡通用到的时光、一些日程类应用等。但电商相关的政工大都不克直接采用设备上的流年,而是用以及服务器校准后底年月,例如:

  • 距离判断:一些优化促销活动要以 app
    端判断时是否当活动期间内。如果用户设备时未按照,会叫用户错误的信,导致投诉。
  • 倒计时:各种秒杀、限时促销、未出订单的失效等的倒计时。如果用户设备时未随,会带倒计时结束后刷新页面,状态并未转之问题。可以测试一下电商大厂的
    app,任意拨表之后倒计时仍是不易的。
  • 同台:如有多少并的需,设备时禁止会造成不可知正确判断数的新老关系,可能会见叫原来数据覆盖新数据,造成数丢失。
  • 央时戳:对于分页的多寡,为了防备新栽的数据造成翻页时数错乱,一个常见的解决方案是呼吁列表时累加岁月戳的参数,后台过滤只展示时间穿之后的数码。如果用户设备表慢了,就见面展示不生时的多少,导致新颁发内容在列表不出现的动静。

得看来,对时这要求是充分广泛的。不过实现起来连无为难,在这边享用一下咱的经历。

解决方案

之所以为解决方案,是坐是意义不单是 app
端加几实施代码,而是前后端配合就的。大概思路如下:

  1. 后端需要举行的:每一个网要的回数据还如包含服务器时时空穿
  2. app 端的纱框架在网要的共用回调处取出时穿
  3. 以服务器时间和地方时间之差值缓存到地面
  4. 亟待运用时常,使用当地时间与缓存的时光不同,算有相应的服务器时间

网络要回调

服务器的年月戳可以加以在 response body
里作为集体字段。在自己之花色里,因为有少量 get 请求,所以在了 response
header 里。代码类似如下:

+ (void)handleSuccessResponse:(id)responseObject operation:(AFHTTPRequestOperation *)operation responseType:(Class)responseClass success:(void (^)(id))successBlock failure:(void (^)(NSError *))failureBlock {
    long long timestamp = [[operation.response.allHeaderFields objectForKey:@"Response-Timestamp"] longLongValue];
    [HAMDateTimeUtils updateServerTime:timestamp];
}

老是网络要成功时更新时间不同之休养存。

一个聊之注意点是,处理 timestamp 最好老用 long long 类型。因为
timestamp 传统上是为毫秒为单位之(虽然在 iOS 这个奇葩系统里
NSTimeInteval 是坐秒为单位),在 32 位系统上 long 和 NSInteger
都满怀不下,会漫起。当然,现在 32 位系统的装置已经不经常表现了。

时刻不同之缓存

以创新缓存时,把服务器时间以及地面当前的时间不同保存在单例里。

HAMDateTimeUtils.m
- (void)updateServerTime:(long long)timestamp {
    NSTimeInterval timeInteval = timestamp / 1000.0 - [[NSDate date] timeIntervalSince1970];
    [self sharedInstance].timeIntevalDifference = timeInteval;
}

供校准过之时日

消采取时常,根据目前光阴以及缓存过的日子不一,计算校准后底光阴:

HAMDateTimeUtils.m
+ (NSDate*)currentTime {
    NSDate* serverDate = [NSDate dateWithTimeIntervalSinceNow:[self sharedInstance].timeIntevalDifference];
    return serverDate;
}

// 以毫秒为单位
+ (long long)currentTimeStamp {
    NSTimeInterval localTime = [[NSDate date] timeIntervalSince1970];
    NSTimeInterval timeDifference = [WNYDateTimeUtils sharedInstance].timeIntevalDifference;

    return (long long)((localTimeStamp + timeDifference) * 1000);
}

运用时不过需要调用 [HAMDateTimeUtils currentTime]
[HAMDateTimeUtils currentTimeStamp] 即可。

讨论

  • Q:这样得出的年华标准吗?
    A:会生得误差。原因在,服务器返回的日戳是从服务器开始回来数据的时,到客户端接收时会见来几许推。不过对此我们的后台天文台,这个延迟一般
    <100 ms,对于我们的工作以来没什么影响。
    若对准确性要求重新胜,可以考虑用专门的对时接口,不明白国家天文台有没出……
    除此以外,这种对常之方案只是用于优化 UI
    层面的显得,不克防止用户恶意之篡改。要一味铭刻客户端的日戳是不可信的,后端业务是利用时还必用服务器的辰。

  • Q:缓存的时候,为什么只存在单例里,不持久化存储?
    A:这个自家为设想了,主要是当重新启航之时光,时间各异或会见发生变化,感觉持久化没有最非常的必需。如果觉得出必不可少的话,也足以当
    userDefault 里抱一卖,启动时取出来即可。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2018 亚洲必赢手机官网 版权所有