0

I am trying to show download progress in my UICollectionView Cell. It has a bug when I reuse the cells, the progress is appearing on wrong cells when I scroll it.

I referred this link and I am doing like that only : Displaying download progress in reusable cells

This is how I am doing it. I have created a model :

class NewsFeedDownload{
    var index: Int?
    var uniqueId: String?
    var cell: UICollectionViewCell?
    var progressBar: CircularProgressBar?
    var progressContainerView: UIView?
    var backgroundView: UIView?
} 

I have variable to store this model data based on unique key :

var downloadList        = [String: NewsFeedDownload]()

I am initializing it in willDisplay cell (tried in cellForItemAt also) like this :

if let uniqueId = self.arObjectList[indexPath.item].id{

    currentCell.downloadBackgroundView.alpha    = 0.0
    currentCell.progressBarContainer.alpha = 0.0
    if !self.downloadList.contains(where: { $0.key == uniqueId }) {
        print("adding object in downloadList : \(indexPath.item, uniqueId)")
        let downloadObject                   = NewsFeedDownload()
        downloadObject.index                 = indexPath.item
        downloadObject.uniqueId              = uniqueId
        downloadObject.cell                  = currentCell
        let progress                         = CircularProgressBar.init(frame: currentCell.progressBarContainer.bounds)
        currentCell.progressBarContainer.addSubview(progress)
        downloadObject.progressContainerView = currentCell.progressBarContainer
        downloadObject.progressBar           = progress
        downloadObject.backgroundView        = currentCell.downloadBackgroundView
        self.downloadList[uniqueId]               = downloadObject

    }
}

I have a progress callback where I am fetching my model object based on key and showing progress on that object :

func downloadProgress(progress: Double, id: String){
   let downloadObect = downloadList[id]
   downloadObect?.progressBar?.showProgress(percent: Float(progress * 100))
   downloadObect?.backgroundView?.alpha = 1.0
   downloadObect?.progressContainerView?.alpha = 1.0
}

And I have one function which checks if there is any download. I am calling this function in cellForItem method :

func checkIfDownloading(){
    for (key, _) in downloadList{
        if VideoDownloader.isDownloading(id: key){
            let downloadObect = downloadList[key]
            if let downloadingCell = downloadObect?.cell as? BreakingNewsCell{
                downloadingCell.downloadBackgroundView?.alpha = 1.0
                downloadingCell.progressBarContainer.alpha = 1.0
                downloadObect?.progressBar?.showProgress(percent: Float(VideoDownloader.getProgressFor(id: key) * 100))
            }else if let downloadingCell = downloadObect?.cell as? NormalNews{
                downloadingCell.downloadBackgroundView?.alpha = 1.0
                downloadingCell.progressBarContainer.alpha = 1.0
                downloadObect?.progressBar?.showProgress(percent: Float(VideoDownloader.getProgressFor(id: key) * 100))
            }

        }else{
            let downloadObect = downloadList[key]
            if let downloadingCell = downloadObect?.cell as? BreakingNewsCell{
                downloadingCell.downloadBackgroundView?.alpha = 0.0
                downloadingCell.progressBarContainer.alpha = 0.0
            }else if let downloadingCell = downloadObect?.cell as? NormalNews{
                downloadingCell.downloadBackgroundView?.alpha = 0.0
                downloadingCell.progressBarContainer.alpha = 0.0
            }
        }
    }
}

In above function I am showing or hiding the progress bar.

What am I doing wrong in this ? How can I fix this bug ?

Sharad Chauhan
  • 4,821
  • 2
  • 25
  • 50

2 Answers2

0

Only get the status of Downloading Progress from the checkIfDownloading method.

Set the status of cell's subviews ( in your case downloadBackgroundView?.alpha ,progressBarContainer.alpha ,progressBar?.showProgress ) in the cellForItem method.

Emtiyaj Ali
  • 180
  • 1
  • 6
  • 13
0

I think it would be better arch if those updates were to come from the view controller :

  • In the cellForItemAt , update the progressView of the cell and the
    status (started, stopped, downloading)
  • Have the VideoDownloader notifying (by NSNotification or delegation) the CollectionViewController each time it starts /
    stops downloading a Newsfeed and each time the progress change for a given Newsfeed.
  • When receiving this information, the CollectionViewController can call the collectionView reloadItemAt method to refresh the cell of the specific Newsfeed.

This way you are sure not to get in the mixup when recycling cell since it's always the cellForItemAt method that will update the cell progress.

Florian Burel
  • 3,408
  • 1
  • 19
  • 20
  • I will try this approach too then. – Sharad Chauhan Mar 28 '18 at 09:48
  • Note that you can use the NSProgress class by adding an NSProgress property to your model, that would be updated by the downloader and "listen to" by the ViewController. This will save you some time and you'll gain by decoupling your classes. – Florian Burel Mar 28 '18 at 10:16