iOS倒數計時設計思路和一個系統時間的坑
個人知識點記錄,僅供參考
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核心方法去獲取)
注意:在確保獲取系統時間準確的情況下,用sysctl,每次請求都需要儲存兩個值,一個是伺服器時間,json返回的,另一個就是這次請求的系統時間。為什麼呢?因為你倒數計時不是每次都會重新請求資料,而且即使你請求資料,你各種開銷到你正真倒數計時的時候,伺服器時間沒變啊,因為你獲取到的伺服器時間是早先請求的時間,這個時候,你剛才儲存的系統時間就有用了,你在每次回去伺服器時間的時候,都需要再重新呼叫sysstl方法獲取最新的系統核心時間,減去你當時請求回來記錄的那個欄位時間,差值就是這段時間系統走過的差值,然後加上你的原先伺服器時間,才是你當前的伺服器時間。然後才能拿這個伺服器時間和倒數計時截止時間,結算出最終用來跑定時器任務的差值,這個值才是最後倒數計時顯示用的
相關文章
- 線上直播系統原始碼,預設倒數計時,自定義輸入時間倒數計時原始碼
- 計算時間差,頁面倒數計時,安卓與ios相容問題安卓iOS
- js實現指定時間倒數計時JS
- JavaScript 倒數計時踩坑集錦JavaScript
- [Unity]記一個倒數計時介面Unity
- 視訊直播系統原始碼,倒數計時顯示,商品秒殺倒數計時原始碼
- iOS倒數計時的探究與選擇iOS
- 倒數計時
- 倒數計時快取時間問題總結快取
- win10 自帶倒數計時如何設定_win10開啟計時器倒數計時的方法Win10
- Flutter倒數計時/計時器的實現Flutter
- JavaScript倒數計時JavaScript
- 商城倒數計時
- 如何使用原生技術寫一個倒數計時時鐘
- linux系統時間程式設計(8) UTC秒數轉本地字串時間Linux程式設計字串
- 直播系統原始碼,實現倒數計時,定時任務原始碼
- 倒數計時(天、時、分、秒)
- 倒數計時34天
- 倒數計時2天!
- 倒數計時1天
- 倒數計時2天
- JavaScript 天小時分鐘和秒倒數計時JavaScript
- 直播小程式原始碼,vue實現時間倒數計時原始碼Vue
- 直播平臺搭建,計時和倒數計時功能的分別實現
- 如何設計一個秒殺系統-許令波-極客時間
- js自動倒數計時程式碼,倒數計時完畢時自動停止迴圈JS
- canvas環形倒數計時Canvas
- 用 bash 倒數計時日期
- Android中handler倒數計時Android
- CountDownTimer使用——android倒數計時Android
- 小程式倒數計時深究
- 點選button倒數計時
- Axure之倒數計時效果
- laravel 9 倒數計時了Laravel
- 如何寫好倒數計時
- 面向Vue新人:寫一個簡單的倒數計時按鈕Vue
- Linux時間設定系統時間、硬體時間和時間服務Linux
- 5 年前他的一個設計思路,讓 TDengine 時間壓縮提升近 50 倍
- 聊一聊實時計算系統設計