在UICollectionViewCell中使用计时器添加倒计时标签的最佳方法,即使在重复使用单元格之后也能正常工作

我有一个在UICollectionView中呈现给用户的项目列表。 这些项目具有倒计时标签,以显示该项目可用的剩余时间。 我在UICollectionViewCell使用了一个Timer来显示剩余时间,如:

 OperationQueue.main.addOperation { var remaingTimeInterval = self.calculateRemainigTime(remainingTime: remainingTime) if remaingTimeInterval > 0 { self.timerLabel.isHidden = false self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] (_) in let hours = Int(remaingTimeInterval) / 3600 let minutes = Int(remaingTimeInterval) / 60 % 60 let seconds = Int(remaingTimeInterval) % 60 self?.timerLabel?.text = String(format:"%02i:%02i:%02i", hours, minutes, seconds) remaingTimeInterval -= 1 }) } else { self.timer?.invalidate() self.timerLabel.isHidden = true } } 

这就是我根据给定日期计算剩余时间的方法:

 //Calculating remaining time based on the item endDate and currentDAte func calculateRemainigTime(remainingTime: String) -> Int { let prizeRemainingTime = Helper.stringToDate(remainingTime) let prizeRemainingTimeInterval = Int(prizeRemainingTime.timeIntervalSince1970) let currentTimeInterval = Int(Date().timeIntervalSince1970) return prizeRemainingTimeInterval - currentTimeInterval } 

一切正常,直到细胞被重复使用,之后倒计时数字不再正确。

这是在UICollectionViewCell中显示倒计时的正确方法,还是有更好的解决方案。

任何人都可以帮我找到解决方法吗?

  • 将计时器逻辑移动到数据模型。
  • 而不是目标/动作使用Timer的基于块的API。
  • cellForRow将计时器回调块传递给单元格。
  • 当计时器触发回调块中的代码时,可以更新单元中的UI。

从接受的答案指南编码,希望你喜欢它。

MyViewController

 protocol MyViewControllerDelegate : class { func updateTimer(_ timeString: String) } class MyViewController: UIViewController { weak var timerDetegate: MyViewControllerDelegate? var timer = Timer() var time = 0 fun ViewDidLoad() { timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in self.time += 1 self.timerDetegate?.updateTimer("time \(self.time)") }) } ... func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableViewdequeueReusableCell(withIdentifier: "MeCell") vc.timerDetegate = cell return cell } ... } 

MyTableViewCell

 class MyTableViewCell : UITableViewCell, MyViewControllerDelegate { ... func updateTimer(_ timeString: String) { lblTimeLeft.text = timeString } } 

我已经实现了这种更简单的方式(不关心性能/延迟)

在..cellForItemAt ..方法中,我打电话

 cell.localEndTime = yourEndTimeInterval cell.startTimerProgress() 

在集合视图单元格中,我添加了一个启动进度的方法:

  var localEndTime: TimeInterval = 0 //set value from model var timer:Timer? func timerIsRunning(timer: Timer){ let diff = localEndTime - Date().timeIntervalSince1970 if diff > 0 { self.showProgress() return } self.stopProgress() } func showProgress(){ let endDate = Date(timeIntervalSince1970: localEndTime) let nowDate = Date() let components = Calendar.current.dateComponents(Set([.day, .hour, .minute, .second]), from: nowDate, to: endDate) self?.timerLabel?.text = String(format:"%02i:%02i:%02i", components.hour!, components.minute!, components.second!) } func stopProgress(){ self?.timerLabel?.text = String(format:"%02i:%02i:%02i", 0, 0, 0) self.timer?.invalidate() self.timer = nil } func startTimerProgress() { timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.timerIsRunning(timer:)), userInfo: nil, repeats: true) self.timer?.fire() }