Search code examples
iosswiftdrawrectcollectionviewsetneedsdisplay

setNeedsDisplay() is not updating collectionViewCell subView's drawRect


I am trying to display a progress indicator inside of a collectionView cell. To do this there is a background thread that sends a notification to the Main Thread to update the progress indicator.

In main view controller...

    func updateProgressIndicator(notification:NSNotification){
        let userInfo = notification.userInfo! as NSDictionary
        let date = userInfo["date"] as! NSDate
        let percentComplete = userInfo["percent"] as! Double

        self.progressIndicator.text = "\(percentComplete)%" // this works
        let dateIndex = self.calendarDates.indexOf(date)
        let indexPath = NSIndexPath(forItem: dateIndex!, inSection: 0)
        let cell = self.collectionView.dequeueReusableCellWithReuseIdentifier("DateCell", forIndexPath: indexPath) as! DateCell
        cell.showProgress()
    }

The function locates the indexPath for the cell to be updated. The cell's showProgress method is then called.

class DateCell: UICollectionViewCell {
    @IBOutlet weak var dotGraph: DotGraphView!

    func showProgress(){
        print("   DateCell showProgress") // this does get printed
        self.setNeedsDisplay()
    }

    override func drawRect(rect: CGRect) {
        print("   DateCell drawRect") // this never gets printed
        //drawing functions go here
    }
}

The showProgress() method is called for the correct cell and the print message is displayed. When the showProgress method calls setNeedsDisplay() however, the drawRect function is never executed.

The only way I've gotten the cell to update is to fully reload the cell using reloadRowsAtIndexPaths, however this should be unnecessary.

Any ideas on how to get the drawRect function to be called?


Solution

  • You say that showProgress() is called for the correct cell, but that seems unlikely. When you call dequeueReusableCellWithReuseIdentifier(_:forIndexPath:), I would expect you to get a different instance of DateCell than the one the collection view is currently displaying. The one being displayed is in use, so it wouldn't be returned from a dequeue... method. You can test whether I'm correct about this by using NSLog on the cell. I expect the address of this one to be different than the one you returned in cellForItemAtIndexPath().

    Rather than dequeuing the cell, you should just put the cell in a property so that everyone uses the same one. That's the cell you should return in cellForItemAtIndexPath() as well.