简体   繁体   中英

Swift | UICollectionView without storyboard shows incorrect data

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 (eg 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()
    }

}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM