One timer per table view cell

后端 未结 1 975
Happy的楠姐
Happy的楠姐 2020-11-27 23:11

I want to tap on table cell and start a timer. Every cell should have its own timer. I have managed to set the timer but not independently, when I set one all cells are set.

相关标签:
1条回答
  • 2020-11-27 23:58

    This is how I would do it:

    • Create a struct to represent each row containing a start time and whether that row is currently running
    • Schedule a repeating timer for 0.5 seconds to account for the jitter in Timer
    • Each time the timer fires, update the visible rows that have "running" timers

    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()
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题