Reputation: 1155
I am building an app that has a UICollectionView with three items. Each item takes up the complete width of the screen and shows a timer that counts down to the next departure times for our busses in each location.
Each item contains 1) the departure address, 2) a string "Next shuttle leaves at time", and 3) a timer that counts down to the next departure time in 00:00:00 format.
Item 1 and 2 display as expected, but when I get to item 3 the departure address and string are correct, but the timer shows the time for cell 1 instead of cell 3.
I am setting the UICollectionView up like:
func setupCollectionView() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.itemSize = frame.size
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
layout.scrollDirection = UICollectionViewScrollDirection.Horizontal
let collFrame:CGRect = CGRectMake(0, 0, self.frame.width, self.frame.height)
collectionView = UICollectionView(frame: collFrame, collectionViewLayout: layout)
collectionView!.dataSource = self
collectionView!.delegate = self
collectionView!.registerClass(NextShuttleCell.self, forCellWithReuseIdentifier: "cell")
collectionView!.backgroundColor = UIColor.whiteColor()
collectionView!.pagingEnabled = true
collectionView!.scrollIndicatorInsets = UIEdgeInsetsZero
collectionView!.layer.borderWidth = 0
collectionView!.layer.borderColor = UIColor.clearColor().CGColor
self.addSubview(collectionView!)
}
And creating the items using:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell:NextShuttleCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! NextShuttleCell
switch(indexPath.row) {
case 0:
cell.setCellColor(help.darkAccent1())
cell.setLocationLabel("Auckland, Victoria Street")
cell.schedule = getScheduleFor("Victoria Street")
case 1:
cell.setCellColor(help.darkAccent2())
cell.setLocationLabel("Wellington, Airedale Street")
cell.schedule = getScheduleFor("Airedale Street")
case 2:
cell.setCellColor(help.darkAccent3())
cell.setLocationLabel("Airport, Auckland")
cell.schedule = getScheduleFor("Auckland Airport")
default: break
}
return cell
}
When this view is instantiated it retrieves the schedule from Parse.com. The getScheduleFor
function then iterates through this schedule and returns the relevant locations schedule object to the custom cell.
I know that the getScheduleFor function is working correctly as it pulls the right information for the first two items, and if I change the order of the items (e.g. swap the item 3 code with item 1, then the correct data shows in item 1 but item 3 is incorrect.
Also note that it is only the timer that is incorrect on item 3, the remaining information is correct and this is pulled from the schedule object as well - so I know it's pulling the right data.
I also moved this into a UITableView and it showed the correct data so it seems to be something to do with the way the UICollectionView manages it's items.
EDIT:
I am using a custom UICollectionViewCell and initialising it using:
override init(frame: CGRect) {
super.init(frame: frame)
initTimer()
}
This gets the next shuttle time and initialises a timer to update the count down label.
func initTimer() {
nextShuttleTime = getNextShuttleTime()
timeTillNextShuttle = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "updateTime", userInfo: nil, repeats: true)
}
Then, it gets the time using the following:
func updateTime() {
let nextShuttleAt:NSTimeInterval = NSTimeInterval(nextShuttleTime.timeIntervalSinceNow)
let currentTime:NSTimeInterval = NSTimeInterval(NSDate().timeIntervalSinceNow)
let timeLeft:NSTimeInterval = nextShuttleAt - currentTime
if timeLeft >= 0 {
let seconds = timeLeft
timeLabel.text = "\(stringFromTimeInterval(seconds))"
self.updateNextShuttleLabel()
} else {
timeTillNextShuttle.invalidate()
initTimer()
}
}
WORKING SOLUTION:
As per the comments, I stopped getNextShuttleTime() from being assigned to a variable and instead called this in the updateTimer() function. Updated as per below:
func initTimer() {
timeTillNextShuttle = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "updateTime", userInfo: nil, repeats: true)
}
func updateTime() {
let nextShuttleAt:NSTimeInterval = NSTimeInterval(getNextShuttleTime().timeIntervalSinceNow)
let currentTime:NSTimeInterval = NSTimeInterval(NSDate().timeIntervalSinceNow)
let timeLeft:NSTimeInterval = nextShuttleAt - currentTime
if timeLeft >= 0 {
let seconds = timeLeft
timeLabel.text = "\(stringFromTimeInterval(seconds))"
self.updateNextShuttleLabel()
} else {
timeTillNextShuttle.invalidate()
initTimer()
}
}
Upvotes: 1
Views: 383
Reputation: 114773
Your NextShuttleCell
objects will be re-used, so you need to make sure that everything is updated when the cell is assigned - you can't rely on init() as this will only be called the first time that a cell is assigned.
Rather than storing the nextShuttleTime
variable in initTimer()
you can call getNextShuttleTime()
in updateTime
- this way you will always get the correct time.
Upvotes: 1