Reputation: 758
I have UITableViewcells
that are created at different moments in time and I would like each one of them to have an independent timer that triggers when the object is added with reloadData()
This is what I have done so far
import UIKit
var timer = Timer()
var blinkStatus:Bool! = false
var time = 300
class LiveViewCell: UITableViewCell {
let str = String(format:"%02d:%02d", (time / 60), (time % 100))
func processTimer() {
if time > 0 {
time -= 1
timeRemainingLbl.text = String(time)
} else if time == 0 {
timer.invalidate()
timeRemainingLbl.text = "Due!"
timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(LiveViewCell.blinkTimer), userInfo: nil, repeats: true)
}
}
func blinkTimer() {
if blinkStatus == false {
timeRemainingLbl.textColor = UIColor(red:1.00, green:0.00, blue:0.00, alpha:1.0)
blinkStatus = true
} else if blinkStatus == true {
timeRemainingLbl.textColor = UIColor.clear
blinkStatus = false
}
}
@IBOutlet weak var tableNumberLeftLabel: UILabel!
@IBOutlet weak var guestNumbersLabel: UILabel!
@IBOutlet weak var timeInTableLabel: UILabel!
@IBOutlet weak var tableNumberLbl: UILabel!
@IBOutlet weak var timeRemainingLbl: UILabel!
var table: Table!
func configureLiveCell(_ NT: Table) {
layer.cornerRadius = 20
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(LiveViewCell.processTimer), userInfo: nil, repeats: true)
tableNumberLbl.text = "T" + String(NT.number)
timeRemainingLbl.text = String(time)
}
}
The problem comes when configureLiveCell
gets called whenever I create a new cell. The timer seems to speed up and I would like each timer to be independent.
Upvotes: 6
Views: 6591
Reputation: 15951
Here is a code to manage timer in UITableview Cell in swift 2.0
IN ViewController
class ViewController: UIViewController, UITableViewDelegate , UITableViewDataSource{
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TblCell", forIndexPath: indexPath) as! TblCell
cell.selectionStyle = .None
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell : TblCell = (tableView.cellForRowAtIndexPath(indexPath) as? TblCell)!
cell.setupTimer(with: indexPath.row)
}
}
IN UITableviewCell
class TblCell: UITableViewCell {
@IBOutlet weak var lblTimer: UILabel!
var couponTimer : NSTimer?
var startTime : NSDate!
var currentIndex : Int = 1
func setupTimer(`with` indexPath: Int){
currentIndex = indexPath + 1
self.startTime = NSDate()
if self.couponTimer != nil {
self.couponTimer?.invalidate()
self.couponTimer = nil
}
couponTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(self.calculateTime), userInfo: nil, repeats: true);
NSRunLoop.currentRunLoop().addTimer(couponTimer!, forMode: NSRunLoopCommonModes)
couponTimer?.fire()
}
func stopTimer(){
if self.couponTimer != nil {
self.couponTimer?.invalidate()
self.couponTimer = nil
}
}
func calculateTime() {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let dateFormatter1 = NSDateFormatter()
dateFormatter1.dateFormat = "yyyy-MM-dd"
let tomorrow = NSCalendar.currentCalendar()
.dateByAddingUnit(
.Day,
value: currentIndex,
toDate: NSDate(),
options: []
)
let tomorrowDate = dateFormatter1.stringFromDate(tomorrow!)
let tomorrowActiveDate = dateFormatter.dateFromString(tomorrowDate + " " + "10:15:00")
let currentDate = NSDate()
let strTimer : String = tomorrowActiveDate!.offsetFrom(currentDate)
self.lblTimer.text = strTimer
self.lblTimer.textColor = UIColor.whiteColor()
self.lblTimer.backgroundColor = UIColor(red: 255.0/255.0, green: 44.0/255.0, blue: 86.0/255.0, alpha: 1.0)
}
}
Extension
extension NSDate {
func offsetFrom(date:NSDate) -> String {
let dayHourMinuteSecond: NSCalendarUnit = [.Day, .Hour, .Minute, .Second]
let difference = NSCalendar.currentCalendar().components(dayHourMinuteSecond, fromDate: date, toDate: self, options: [])
var seconds : String = ""
var minutes : String = ""
var hours : String = ""
var days : String = ""
let tmp1 : String = String(format: "%.2d", difference.second)
let tmp2 : String = String(format: "%.2d", difference.minute)
let tmp3 : String = String(format: "%.2d", difference.hour)
let tmp4 : String = String(format: "%d", difference.day)
seconds = "\(tmp1)"
minutes = "\(tmp2)" + ":" + seconds
hours = "\(tmp3)" + ":" + minutes
days = "\(tmp4)d" + " " + hours
if difference.second >= 0 && difference.minute >= 0 && difference.hour >= 0 && difference.day >= 0 {
return days
}
else {
return ""
}
}
}
Upvotes: 0
Reputation: 318774
Override the prepareForReuse
method.
override func prepareForReuse() {
super.prepareForReuse()
timer.invalidate()
}
This will be called just before a cell is returned to be used by another row. By invalidating the timer here, your configureLiveCell
doesn't create yet another timer.
BTW - you should also add a deinit
method and invalidate the timer there too.
You also make the timer
property optional and set it to nil
after you invalidate it. And of course you need to add proper checks to deal with it being an optional.
And one last change you must make is to change timer
, time
, and blinkStatus
so they are instance variables by moving them inside the class.
Upvotes: 11