【问题标题】:One timer per table view cell每个表格视图单元格一个计时器
【发布时间】:2018-08-21 02:39:51
【问题描述】:

我想点击表格单元格并启动一个计时器。每个单元格都应该有自己的计时器。我设法设置了计时器,但不是独立设置的,当我设置一个时,所有单元格都设置好了。

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    let currentCell = tableView.cellForRow(at: indexPath) as! StaffTableViewCell

    if isRunning == false {



        currentCell.cellImageView.image = UIImage(data: UIImagePNGRepresentation(#imageLiteral(resourceName: "greendot"))!)


        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in

            counter += 1
            let hourPortion = String(format: "%02d", counter / 3600)
            let minutesPortion = String(format: "%02d", counter / 60)
            let secondsPortion = String(format: "%02d", counter % 60)
            //print("\(hourPortion):\(minutesPortion):\(secondsPortion)")

            timeTotal = "\(hourPortion):\(minutesPortion):\(secondsPortion)"

            currentCell.timerLabel.text = timeTotal


            isRunning = true

        }


    }

    tableView.reloadData()


}

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {

    timer.invalidate()
    isRunning = false

    let currentCell = tableView.cellForRow(at: indexPath) as! StaffTableViewCell

    if let data = UIImagePNGRepresentation(#imageLiteral(resourceName: "reddot")) {
        currentCell.cellImageView.image = UIImage(data: data)
    }



    tableView.reloadData()
}

【问题讨论】:

  • 只有一个计时器,每次触发时,更新有“计时器运行”的单元格中的经过时间。
  • 我已经尝试过 Paulw11 但我是初学者并且做得不好,所以我需要编码方面的帮助。谢谢
  • @Paulw11 在计时器运行时,您会使用什么方法来更新各个单元格中的值?
  • 我正在使用领域数据库,但这是我拥有的所有代码,谢谢

标签: ios swift uitableview cocoa-touch


【解决方案1】:

我会这样做:

  • 创建一个结构来表示包含开始时间以及该行当前是否正在运行的每一行
  • Timer 中的抖动安排一个 0.5 秒的重复计时器
  • 每次计时器触发时,更新具有“正在运行”计时器的可见行

import UIKit

struct TimerModel {
    private var startTime: Date?
    private var offset: TimeInterval = 0

    var elapsed : TimeInterval {
        get {
            return self.elapsed(since:Date())
        }
    }

    var isRunning = false {
        didSet {
            if isRunning  {
                self.startTime = Date()
            } else {
                if self.startTime != nil{
                    self.offset = self.elapsed
                    self.startTime = nil
                }
            }
        }
    }

    func elapsed(since: Date) -> TimeInterval {
        var elapsed = offset
        if let startTime = self.startTime {
            elapsed += -startTime.timeIntervalSince(since)
        }
        return elapsed
    }
}

class ViewController: UIViewController {

    @IBOutlet weak var tableview: UITableView!

    var timer: Timer?
    var timersActive = 0

    let formatter: DateComponentsFormatter = {
        let formatter = DateComponentsFormatter()
        formatter.zeroFormattingBehavior = .pad
        formatter.allowedUnits = [.hour, .minute, .second]
        return formatter
    }()

    var timers = [TimerModel](repeating:TimerModel(), count:30)


    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func elapsedTimeSince(_ startTime: Date) -> String {
        let elapsed = -startTime.timeIntervalSinceNow

        return self.formatter.string(from: elapsed) ?? "0:00:00"
    }

    func startTimer() {
        self.timersActive += 1
        guard self.timer == nil else {
            return
        }

        self.timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { [weak self] (timer) in
           if let me = self {
            for indexPath in me.tableview.indexPathsForVisibleRows ?? [] {
                let timer = me.timers[indexPath.row]
                if timer.isRunning {
                    if let cell = me.tableview.cellForRow(at: indexPath) {
                        cell.textLabel?.text = me.formatter.string(from: timer.elapsed) ?? "0:00:00"
                    }
                }
            }
           }
        })
    }

    func stopTimer() {
        self.timersActive -= 1
        if self.timersActive == 0 {
            self.timer?.invalidate()
            self.timer = nil
        }
    }

}

extension ViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.timers.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        let timer = self.timers[indexPath.row]

        cell.imageView?.image = timer.isRunning ? #imageLiteral(resourceName: "GreenDot") : #imageLiteral(resourceName: "RedDot")
        cell.textLabel?.text = self.formatter.string(from: timer.elapsed) ?? "0:00:00"

        return cell
    }
}

extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.timers[indexPath.row].isRunning = !self.timers[indexPath.row].isRunning
        self.tableview.reloadRows(at: [indexPath], with: .none)
        if self.timers[indexPath.row].isRunning {
            self.startTimer()
        } else {
            self.stopTimer()
        }
    }
}

【讨论】:

  • 谢谢 Paulw11,我希望它从计时器停止的地方开始,而不是从零开始。你能帮忙吗?谢谢
  • 我已经更新了我的答案,这样您就可以在不重置计时器的情况下启动和停止并重新启动计时器。
  • 谢谢你,我真的很感激!
  • 嗨@Paulw11,一切正常,但我正在努力解决的一件事是,如果我刷新应用程序并启动计时器,它将不会从它离开的地方开始并从零开始,我想保持价值,我尝试了很多方法 userdefault ,但没有任何效果。你能告诉我如何保存定时器的用户默认值吗?谢谢
  • 我不会使用 UserDefaults。我会使用核心数据。它具有更大的学习曲线,但它是保存数据的更好方法。如果你需要帮助,你应该问另一个问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-29
  • 1970-01-01
相关资源
最近更新 更多