iOS 开发#iOS#HeminWoniOS

iOS 时间校准解决方案

2016-12-07  本文已影响1548人  戴仓薯

背景

在 iOS 开发中,凡是用到系统时间的,都要考虑一个问题:对时。有些业务是无需对时,或可以以用户时间为准的,比如动画用到的时间、一些日程类应用等。但电商相关的业务大都不能直接使用设备上的时间,而是需要跟服务器校准后的时间,例如:

可以看出,对时这个需求是非常普遍的。不过实现起来并不难,在这里分享一下我们的经验。

解决方案

之所以叫解决方案,是因为这个功能不单是 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] 即可。

讨论

上一篇下一篇

猜你喜欢

热点阅读