I have a collectionView that contains timers in each cell. When the app starts all the timers work fine, however, when I refresh the collection view all the timers get mixed up and are all over the place. I am pretty sure it has something to do with the previous timers not closing.
Code for collection view:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "contestsCell", for: indexPath) as! ContestsCollectionViewCell
cell.nameLabel.text = listingArray[indexPath.row].name
let arr = [listingArray[indexPath.row].expiryDate, cell.expiryDateLabel] as [AnyObject]
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateCounting), userInfo: arr, repeats: true)
return cell
}
Code for timer function:
@objc func updateCounting(timer:Timer){
// here we set the current date
var dateArray: [AnyObject] = timer.userInfo as! [AnyObject]
let itemDate = dateArray[0] as! String
var dateList = itemDate.components(separatedBy: "-")
let dateLabel = dateArray[1] as! UILabel
let date = NSDate()
let calendar = Calendar.current
let components = calendar.dateComponents([.hour, .minute, .month, .year, .day, .second], from: date as Date)
let currentDate = calendar.date(from: components)
let userCalendar = Calendar.current
// here we set the due date. When the timer is supposed to finish
let competitionDate = NSDateComponents()
competitionDate.year = Int(dateList[0])!
competitionDate.month = Int(dateList[1])!
competitionDate.day = Int(dateList[2])!
competitionDate.hour = 00
competitionDate.minute = 00
competitionDate.second = 00
let competitionDay = userCalendar.date(from: competitionDate as DateComponents)!
//here we change the seconds to hours,minutes and days
let CompetitionDayDifference = calendar.dateComponents([.day, .hour, .minute, .second], from: currentDate!, to: competitionDay)
//finally, here we set the variable to our remaining time
let daysLeft = CompetitionDayDifference.day
let hoursLeft = CompetitionDayDifference.hour
let minutesLeft = CompetitionDayDifference.minute
let secondsLeft = CompetitionDayDifference.second
if competitionDay > currentDate as! Date {
//Set countdown label text
dateLabel.text = "\(daysLeft ?? 0): \(hoursLeft ?? 0): \(minutesLeft ?? 0): \(secondsLeft ?? 0)"
}
}
code for refreshing collectionView
@objc func loadData() {
retrieveContests()
listingArray.removeAll()
self.refresher.endRefreshing()
}
I think your problem has to do with the fact that you dequeue your cells. Since the principle behind this is that existing cell objects are being reused by iOS that might lead to some problems.
E.g. in the method you create cell1 with countdown1 and a timer and the same with cell2 and countdown2 (+timer). Once you reload your collectionView cell1 and cell2 will be reused, but now cell1 will have a different index path and is therefor used for countdown2 and also a new timer is created as well.
This probably leads to the problem that your timers are getting mixed up in the process and as far as I can see in your code you are also never stopping any timers, so your assumption is correct I would say. Every time you reload your collection view, your are creating more timers.
My suggestion to solve this would be: Create a property on each cell that contains the Date-object which you use to calculate the countdown. Then just use a single timer which notifies all cells to update their content on their own. Maybe you could use NotificationCenter for this. This (or a similar approach) should help you and avoid the whole problem with maintaining all these timers.