版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2017.08.30 |
前言
很多時候我們是需要服務器和客戶端時間的同步的,比如說活動的倒計時,搶購等。而且做好時間同步還有一個優勢就是防止客戶端用戶本地時間有誤差導致問題。感興趣的可以看上面幾篇。
1. iOS關于時間的處理(一)—— 有關時間的基本知識
功能要求
要做到客戶端和服務器端時間同步。
功能實現
1. 問題分析
我們可以按照下面的思路進行
- 獲取服務器某一時刻
A
的時間; - 記錄獲取到時刻
A
時的本地時間B
; - 需要用到時間時,獲取當前本地時間
C
,當C - B
作為時間間隔D
,則A + D
則是當前服務器的時間。
這里要準確做到客戶端時間和服務器時間一致,很關鍵的問題就是B和C不能受系統時間的影響。要解決這個問題,要依靠iOS的兩個接口。
- 獲取設備當前時間
Now
,該值受系統時間影響,用戶如果修改時間,值也會隨著變化。 - 獲取設備上次重啟的時間
BootTime
,該值受系統時間影響,用戶如果修改時間,值也會隨著變化。
由上面 iOS 提供的兩個接口,我們可以獲取本地時間 B
、C
:設備自上次重啟后運行的時間(BootTime - Now)
,該值與系統時間無關。利用時間差這一概念就很好的解決了時間受系統影響的這個問題了。
2. 代碼實現
- 獲取當前
Unix Time
static func now() -> Int {
var now = timeval()
var tz = timezone()
gettimeofday(&now, &tz)
return now.tv_sec
}
- 獲取設備上次重啟的
Unix Time
func boottime() -> Int {
var mid = [CTL_KERN, KERN_BOOTTIME]
var boottime = timeval()
var size = MemoryLayout.size(ofValue: boottime)
if sysctl(&mid, 2, &boottime, &size, nil, 0) != -1 {
return boottime.tv_sec
}
return 0
}
- 進行時間校準
// 接口獲取服務器時間處理
let serverTime = xxx // 獲取到的服務器時間
let runTime0 = now() - boottime() // 當前設備運行時間
// 需要用到時間時
let runTime1 = now() - boottime() // 當前時刻設備運行時間
let currentTime = serverTime + runTime1 // 當前服務器時間
題外話
關于時間的使用,還有另外一個用途就是時間的測量,在做方法執行時間的benchmark
的時候,我們獲取時間的方法要滿足兩個要求,一是精讀要高,而是API本身幾乎不耗CPU時間。一般認為UI線程只要阻塞16.7ms
就會出現掉幀現象,第一篇中提到的幾種時間的方法,其中NSDate
調用返回的精讀是0.000004 S
,也就是4微秒,CACurrentMediaTime()
返回的精讀也在微秒級別,精讀上都符合要求。
下面看一下別人提供的示例代碼
int testCount = 10000;
double avgCost = 0;
for (int i = 0; i < testCount; i ++) {
NSDate* begin = [NSDate date];
NSLog(@"a meaningless log");
avgCost += -[begin timeIntervalSinceNow];
}
NSLog(@"benchmark with NSDate: %f", avgCost/testCount);
avgCost = 0;
for (int i = 0; i < testCount; i ++) {
double startTime = CACurrentMediaTime();
NSLog(@"a meaningless log");
double endTime = CACurrentMediaTime();
avgCost += (endTime - startTime);
}
NSLog(@"benchmark with CACurrentMediaTime: %f", avgCost/testCount);
下面看輸出結果
benchmark with NSDate: 0.000046
benchmark with CACurrentMediaTime: 0.000037
可以看出CACurrentMediaTime
與NSDate
代碼本身的損耗差異在幾微秒,而我們做UI性能優化的維度在毫秒級別,幾個微秒的差異完全不會影響我們最后的判斷結果。所以使用NSDate做benchmark完全是可行的。
參考文章
1. iOS 客戶端與服務端做時間同步
2. iOS關于時間的處理