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.
This is how I would do it:
Timer
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()
}
}
}