计时器在iOS中的UITableView单元格中无法正常工作



我正在表视图单元格的类中创建一个计时器,并使用计时器每秒更新一个标签。但是,对于某些单元格,标签每秒更新多次,而对于其他单元格,标签则以不同的速率更新。我认为细胞的可重用性可能会导致问题。

我正在创建计时器对象作为实例变量:

var timer: Timer!

和呼叫:

runTimer(). //called in awakefromnib

而运行时方法是:

func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true)
}
func updateTimer() {
seconds -= 1
timerLabel.text = timeString(time: seconds)
}

创建计时器的正确方法是什么,该计时器根据单元格中的某些登录UILabel每秒更新每个单元格?

编辑: 这如果我的单元格在:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Doubts Cell", for: indexPath) as! DoubtsTableViewCell
cell.postedQuestionAndAnswer = postedQuestionsArray[indexPath.row]
if cell.timer != nil {
cell.timer.invalidate()
}
cell.runTimer()
return cell
}

这是我所需的单元格的类代码:

var postedQuestionAndAnswer: PostedQuestionAndAnswer! {
didSet {
configureTableViewData()
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
func configureTableViewData() {
//.....other code
seconds = getTimeRemaining(queryPostedTime: Double(postedQuestionAndAnswer.question!.createdAt), queryPostedDate: Double(postedQuestionAndAnswer.question!.createdAt))
}
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true)
}
func updateTimer() {
seconds -= 1
timerLabel.text = timeString(time: seconds) //timestring returns desired formatted string
}

最好在视图中创建一个包含Timer和秒的struct数组,例如:

struct MyTimer {
var timer: Timer?
var seconds: Int
init (seconds: Int) {
self.seconds = seconds
}
}

这样声明:

var timers = [[MyTimer(seconds: 5), MyTimer(seconds: 6)],
[MyTimer(seconds: 3), MyTimer(seconds: 4), MyTimer(seconds: 3), MyTimer(seconds: 4), MyTimer(seconds: 3), MyTimer(seconds: 4), MyTimer(seconds: 3), MyTimer(seconds: 4), MyTimer(seconds: 3), MyTimer(seconds: 4), MyTimer(seconds: 3), MyTimer(seconds: 4), MyTimer(seconds: 3), MyTimer(seconds: 4), MyTimer(seconds: 3), MyTimer(seconds: 4), MyTimer(seconds: 3), MyTimer(seconds: 4), MyTimer(seconds: 3), MyTimer(seconds: 4)]]

然后,您需要在每次计时器尚不存在时创建计时器。

func cellForRow(at indexPath: IndexPath) -> UITableViewCell? {
if self.timers[indexPath.section][indexPath.row].timer == nil {
self.timers[indexPath.section][indexPath.row].timer = self.createTimer(indexPath: indexPath)
}
// retrieve your cell here
cell.timerLabel.text = String(self.timers[indexPath.section][indexPath.row].seconds)
return cell
}

要创建计时器,它可以像:

func createTimer (indexPath: IndexPath) -> Timer {
let timeInterVal = self.getTimeInterval(indexPath: indexPath)
let timer = Timer.scheduledTimer(timeInterval: timeInterVal,
target: self,
selector: #selector(updateTimer(sender:)),
userInfo: ["indexPath": indexPath],
repeats: true)
return timer
}
func getTimeInterval (indexPath: IndexPath) -> TimeInterval {
return 1 // or return a value depending on the indexPath
}

然后,要更新计时器:

@objc func updateTimer (sender: Timer) {
guard
let userInfo = sender.userInfo as? [String: IndexPath],
let idx = userInfo["indexPath"] else {
return
}
self.timers[idx.section][idx.row].seconds = self.timers[idx.section][idx.row].seconds - 1
if
let indexPathes = self.tableView.indexPathsForVisibleRows,
indexPathes.contains(idx) {
self.tableView.reloadRows(at: [idx], with: .none) // update directly the cell if it's visible
}
}

如果我理解正确,你只需要一个计时器。将其移动到您的视图控制器。在updateTimer()中,只调用tableView.reloadData()来一次更新所有单元格。在您的单元格中添加 timerLabel.text = timeString(time: seconds) 到 configureTableViewData() 的末尾,并删除与计时器相关的所有内容。

这样,您的所有单元格将每秒更新一次,并且将为每个单元格调用 configureTableViewData() 以相应地更新标签。

宁愿有 1 个计时器并重新加载您的表视图,您的 tableViewCell 不应该有任何自定义逻辑,而是抽象它们的父级。

例:

class TableViewController: UITableViewController {
var timer: Timer
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
runTimer()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
timer.invalidate()
}
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true)
}
func updateTimer() {
self.tableView.reloadData()
}
func getTimeIntervalForTableViewCell() -> TimeInterval { // Not sure what the 'seconds' object type is meant to be so I just used TimeInterval
seconds = getTimeRemaining(queryPostedTime: Double(postedQuestionAndAnswer.question!.createdAt),
queryPostedDate: Double(postedQuestionAndAnswer.question!.createdAt))
return seconds
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Doubts Cell", for: indexPath) as! DoubtsTableViewCell
// rest of your databinding logic here
let timeInterval = self.getTimeIntervalForTableViewCell()
cell.timerLabel.text = timeString(time: timeInterval)
return cell
}
}

最新更新