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

时间:2018-02-06 11:18:43

标签: ios swift uitableview timer nstimer

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

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

var timer: Timer!

并致电:

runTimer(). //called in awakefromnib

而runtimer方法是:

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

编辑: 如果我的cellforrowAt:

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
}

3 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

相反,有1个计时器,只是重新加载你的tableview,你的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
    }
}

答案 2 :(得分:0)

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

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
    }
}