Ive been searching for a answer to this one for days now and cant seem to figure it out. I have a Collection View with custom cell. When you double tap a cell in the Collection View it will either download a file or delete it if its been downloaded before.
During the download a progress bar displays the progress of the download then displays a small icon in the top left corner. When deleting it removes the icon.
If you download from one cell and delete from another while first download is in progress it works fine but only if both cells were visible within the collection view.
if i download from one cell, then scroll offscreen and delete from a cell that is not in same screen as the cell that is being download from, it removes the corner image as usual then displays the progress bar of the cell that is being download from.
I don't know if this is an error with how i am reusing cells??? It doesn't seem to have anything to do with how i am updating the cell or collection view which works in all cases except after scrolling.
Below is 2 functions that download or delete file:
func downloadDataToDevice(cell: JourneyCollectionViewCell, selectedIndexPath: IndexPath){
let downloadedAudio = PFObject(className: "downloadedAudio")
// save all files with unique name / object id
let selectedObjectId = self.partArray[selectedIndexPath.item].id
let selectedPartName = self.partArray[selectedIndexPath.item].name
let query = PFQuery(className: "Part")
query.whereKey("objectId", equalTo: selectedObjectId)
query.getFirstObjectInBackground { (object, error) in
if error != nil || object == nil {
print("No object for the index selected.")
} else {
//print("there is an object, getting the file.")
downloadedAudio.add(object?.object(forKey: "partAudio") as! PFFile, forKey: selectedPartName)
let downloadedFile = object?.object(forKey: "partAudio") as! PFFile
// get the data first so we can track progress
downloadedFile.getDataInBackground({ (success, error) in
if (success != nil) {
// pin the audio if there is data
downloadedAudio.pinInBackground(block: { (success, error) in
if success {
// reload the cell
self.reloadCell(selectedIndexPath: selectedIndexPath, hideProgress: true, hideImage: false, cell: cell)
self.inProgress -= 1
cell.isUserInteractionEnabled = true
}
})
}
// track the progress of the data
}, progressBlock: { (percent) in
self.activityIndicatorView.stopAnimating()
cell.progessBar.isHidden = false
//cell.progessBar.transform = cell.progessBar.transform.scaledBy(x: 1, y: 1.1)
cell.contentView.bringSubview(toFront: cell.progessBar)
cell.progessBar.setProgress(Float(percent) / Float(100), animated: true)
cell.isUserInteractionEnabled = false
})
}
}
}
func removeDataFromDevice(cell: JourneyCollectionViewCell, selectedIndexPath: IndexPath, object: PFObject) {
let selectedPartName = self.partArray[selectedIndexPath.item].name
// unpin the object from the LocalDataStore
PFObject.unpinAll(inBackground: [object], block: { (success, error) in
if success {
// reduce inProgress
self.inProgress -= 1
self.reloadCell(selectedIndexPath: selectedIndexPath, hideProgress: true, hideImage: true, cell: cell)
}
})
}
and this is how I'm reloading the cell
func reloadCell(selectedIndexPath: IndexPath, hideProgress: Bool, hideImage: Bool, cell: JourneyCollectionViewCell) {
cell.progessBar.isHidden = hideProgress
cell.imageDownloaded.isHidden = hideImage
self.collectionView.reloadItems(at: [selectedIndexPath])
}
----------- EDIT -------------
This is my cellForItem at function. Presently i am using a query to look on local drive and see if the file exists and then adding the corner image if it is. This is the first time i have used a query in this place, usually it is a query at login to populate an array but that is for a more static collection of data than what i am trying to achieve here by letting the user download and delete files.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: JourneyCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! JourneyCollectionViewCell
cell.imageCell.file = self.partArray[indexPath.item].image
cell.imageCell.loadInBackground()
cell.imageCell.layer.masksToBounds = true
// not sure if its good to run a query here as its constantly updated.
// query if file is on LDS and add image to indicate
let cellPartName = self.partArray[indexPath.item].name
let checkQuery = PFQuery(className: "downloadedAudio")
checkQuery.whereKeyExists(cellPartName)
checkQuery.fromLocalDatastore()
checkQuery.getFirstObjectInBackground(block: { (object, error) in
if error != nil || object == nil {
//print("The file does not exist locally on the device, remove the image.")
cell.imageDownloaded.isHidden = true
cell.imageDownloaded.image = UIImage(named: "")
cell.progessBar.isHidden = true
} else {
//print("the file already exists on the device, add the image.")
cell.contentView.bringSubview(toFront: cell.imageDownloaded)
cell.imageDownloaded.isHidden = false
cell.imageDownloaded.image = UIImage(named: "download-1")
}
})
return cell
}
So i tried placing the progress view programatically, i tried prepareForReuse in the custom cell class, neither resolved this issue directly, though i will keep using prepareForReuse as i think its a cleaner way to manage the cell than i had been.
What seems to have worked was relocating the cell within the progressBlock
if let downloadingCell = self.collectionView.cellForItem(at: selectedIndexPath) as? JourneyCollectionViewCell { downloadingCell.progessBar.isHidden = false
downloadingCell.contentView.bringSubview(toFront: downloadingCell.progessBar)
downloadingCell.progessBar.setProgress(Float(percent) / Float(100), animated: true)
downloadingCell.setNeedsDisplay()
downloadingCell.isUserInteractionEnabled = false
}