一.前言
之前的文章iOS 在cell中使用倒計時的處理方法得到大量的支持, 在這先感謝大家的支持. 但是也收到不少人的回復表示不會用, 需要一一解答, 由于之前寫的時候沒有使用Markdown編輯, 所以現(xiàn)在沒法更新之前的文章, 重新寫一份清晰的文章
需求: 每條Cell中顯示倒計時, 并隨時間進行倒數(shù)
語言: Objective-C & Swift
系統(tǒng): iOS
Github地址: OYCountDownManager v2.0
OYCountDownManager-Swift v2.0
二.原理分析
原理分析圖.png
單個列表倒計時.gif
v2.0新增
* 多個列表倒計時
* 多個頁面倒計時
* 分頁列表倒計時
* 后臺模式倒計時
多個列表倒計時.gif
多個頁面倒計時.gif
分頁列表倒計時.gif
三.使用方法
1.1 第一種方法: 使用cocoapods自動安裝
pod 'OYCountDownManager'
1.2 第二種方法
下載示例Demo, 把里面的OYCountDownManager文件夾拖到你的項目中
2. 在第一次使用的地方調用[kCountDownManager start]
- (void)viewDidLoad {
[super viewDidLoad];
// 啟動倒計時管理
[kCountDownManager start];
}
3. 在Cell初始化中監(jiān)聽通知 kCountDownNotification
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
// 監(jiān)聽通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(countDownNotification) name:kCountDownNotification object:nil];
}
return self;
}
4. 在cell設置通知回調, 取得時間差, 根據(jù)時間差進行處理
- (void)countDownNotification {
/// 計算倒計時
NSInteger countDown = [self.model.count integerValue] - kCountDownManager.timeInterval;
if (countDown <= 0) {
// 倒計時結束時回調
xxxx(使用代理或block)
}return;
/// 重新賦值
self.timeLabel.text = [NSString stringWithFormat:@"倒計時%02zd:%02zd:%02zd", countDown/3600, (countDown/60)%60, countDown%60];
}
5. 當刷新數(shù)據(jù)時,調用reload方法
- (void)reloadData {
// 網(wǎng)絡加載數(shù)據(jù)
// 調用[kCountDownManager reload]
[kCountDownManager reload];
// 刷新
[self.tableView reloadData];
}
6. 當不需要倒計時時, 廢除定時器
[kCountDownManager invalidate];
四.高級使用(多列表.多頁面.分頁列表)
增加identifier:標識符, 一個identifier支持一個倒計時源, 有一個單獨的時間差
/** 添加倒計時源 */
- (void)addSourceWithIdentifier:(NSString *)identifier;
/** 獲取時間差 */
- (NSInteger)timeIntervalWithIdentifier:(NSString *)identifier;
/** 刷新倒計時源 */
- (void)reloadSourceWithIdentifier:(NSString *)identifier;
/** 刷新所有倒計時源 */
- (void)reloadAllSource;
/** 清除倒計時源 */
- (void)removeSourceWithIdentifier:(NSString *)identifier;
/** 清除所有倒計時源 */
- (void)removeAllSource;
以一個頁面有兩個獨立的列表為例
1.定義identifier(常量)
NSString *const OYMultipleTableSource1 = @"OYMultipleTableSource1";
NSString *const OYMultipleTableSource2 = @"OYMultipleTableSource2";
2.增加倒計時源
// 增加倒計時源
[kCountDownManager addSourceWithIdentifier:OYMultipleTableSource1];
[kCountDownManager addSourceWithIdentifier:OYMultipleTableSource2];
3.在cell通知回調中, 通過identifier取得時間差, 根據(jù)時間差進行處理
- (void)countDownNotification {
/// 判斷是否需要倒計時 -- 可能有的cell不需要倒計時,根據(jù)真實需求來進行判斷
if (0) {
return;
}
/// 計算倒計時
OYModel *model = self.model;
/// 根據(jù)identifier取得時間差, 以OYMultipleTableSource1為例
NSInteger timeInterval = timeInterval = [kCountDownManager timeIntervalWithIdentifier: OYMultipleTableSource1];
}
NSInteger countDown = model.count - timeInterval;
/// 當?shù)褂嫊r到了進行回調
if (countDown <= 0) {
self.detailTextLabel.text = @"活動開始";
// 倒計時結束時回調
xxxx(使用代理或block)
return;
}
/// 重新賦值
self.detailTextLabel.text = [NSString stringWithFormat:@"倒計時%02zd:%02zd:%02zd", countDown/3600, (countDown/60)%60, countDown%60];
}
4. 當刷新數(shù)據(jù)時,調用reloadSourceWithIdentifier:刷新時間差
- (void)reloadData {
// 網(wǎng)絡加載數(shù)據(jù)
// 調用reloadSourceWithIdentifier:刷新時間差
[kCountDownManager reloadSourceWithIdentifier:OYMultiplePageSource1];
// 刷新
[self.tableView reloadData];
}
5. 當頁面銷毀, 移除倒計時源, 或者不需要定時器, 廢除定時器
// 移除所有倒計時源
[kCountDownManager removeAllSource];
// 廢除定時器
[kCountDownManager invalidate];
五.注意事項
誤差分析
- NSTimer可以精確到50-100毫秒,不是絕對準確的,所以使用時間累加的方法時間久了有可能成為時間誤差的來源
- 為秒為單位觸發(fā)定時器, 當reloadData后, 定時器也許剛好到達觸發(fā)點, 時間差+1, 數(shù)據(jù)剛reload完就馬上-1秒
- 后臺模式是以進入后臺的本地時間, 及進入前臺的本地時間做差值來計算的, 當用戶手動修改本地時間, 也會成為時間差錯誤的來源之一, 如果能在進入前臺的時間再從服務器取一次數(shù)據(jù), 或者記錄服務器時間而不是本地時間, 也可以避免這一誤差
滾動cell時出去文字閃爍
在給cell的模型賦值后, 最好手動調用一下countDownNotification方法, 保證及時刷新
/// 重寫setter方法
- (void)setModel:(Model *)model {
_model = model;
self.titleLabel.text = model.title;
// 手動調用通知的回調
[self countDownNotification];
}
倒計時為0后出現(xiàn)復用問題
在倒計時為0后, 應該回調給控制器, 從后臺請求一次數(shù)據(jù), 保證倒計時沒有出現(xiàn)誤差
if (countDown <= 0) {
// 倒計時結束時回調
xxxx(使用代理或block)
}return;
出現(xiàn)每秒倒計時減2的問題
1.查看定時器設置是否正確, 或者通知是否監(jiān)聽了兩次
2.在countDownNotification方法中, 是否用[NSDate date]做了某些計算, 因為[NSDate date]為當前時間, 每一秒去取都會比上一秒大一秒, 再加上timeInterval也是一秒加一, 那么就會出現(xiàn)每秒倒計時減2的問題
如果還有不懂的問題, 或者出現(xiàn)其它bug
請查看Demo: Demo
或者給我留言, 喜歡的話, 就給作者一個star