Reputation: 31
I have a Tableview with multiple cells of the same class. On changing the switch within the cell, a specific file should be downloaded.
Actual behaviour: The correct switch is changing its state and it is also stored even when scrolling away, so this is not the problem. The countryDesignator is correct when starting the download, it is also the correct file when finished, but when the file is stored, it uses the wrong countryDesignator and the progressBar is also wrong. In this particular case, hitting Canada will lead to a download of file [..]ca_asp.aip and the switch in the Canada cell changed, but the progressBar of the cell Austria is moving and the stored file is called at_asp_aip.
Code:
var countrySettings : [countryOptions] = [countryOptions(name: "Austria", isEnabled: false, progress: 0.0, filename: "at"),
countryOptions(name: "Australia", isEnabled: false, progress: 0.0, filename: "au"),
countryOptions(name: "Brazil", isEnabled: false, progress: 0.0, filename: "br"),
countryOptions(name: "Canada", isEnabled: false, progress: 0.0, filename: "ca"), ...]
var downloadCount : Int = 0
class CountrySettings: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var countryTableView: UITableView!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Country") as! countryCell
cell.countryName.text = countrySettings[indexPath.row].name
cell.countrySwitch.isOn = countrySettings[indexPath.row].isEnabled
cell.countryDesignator = countrySettings[indexPath.row].filename
return cell
}
class countryCell: UITableViewCell, URLSessionDownloadDelegate,UIDocumentInteractionControllerDelegate {
@IBOutlet weak var countrySwitch: UISwitch!
@IBOutlet weak var countryName: UILabel!
var countryDesignator : String = "ad"
@IBAction func didChangeSwitchValue(_ sender: UISwitch) {
guard let indexPath = self.indexPath else { return }
downloadCount = 0
print(countryDesignator) // prints correct Designator
startDownloading()
}
func startDownloading () {
guard let indexPath = self.indexPath else { return }
countrySettings[indexPath.row].isEnabled = countrySwitch.isOn
DispatchQueue.main.async {
print(self.countryDesignator) // prints correct Designator
downloadCount += 1
if downloadCount == 1 {
let url = URL(string: "https://www.blablabla.com/" + self.countryDesignator + "_asp.aip")!
self.downloadTask = self.defaultSession.downloadTask(with: url)
self.downloadTask.resume()
}
}
}
// MARK:- URLSessionDownloadDelegate
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print(countryDesignator) // prints WRONG!
print("File download succesfully")
let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let documentDirectoryPath:String = path[0]
let fileManager = FileManager()
var destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appendingFormat("/" + countryDesignator + "_asp.aip"))
if downloadCount == 2 {
destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appendingFormat("/" + countryDesignator + "_wpt.aip"))
}
if fileManager.fileExists(atPath: destinationURLForFile.path){
showFileWithPath(path: destinationURLForFile.path, completePath: destinationURLForFile)
print(destinationURLForFile.path)
}
else{
do {
try fileManager.moveItem(at: location, to: destinationURLForFile)
// load data into database
showFileWithPath(path: destinationURLForFile.path, completePath: destinationURLForFile)
}catch{
print("An error occurred while moving file to destination url")
}
}
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
DispatchQueue.main.async {
print(self.countryDesignator) // prints WRONG
guard let indexPath = self.indexPath else { return }
self.progress.setProgress(Float(totalBytesWritten)/Float(totalBytesExpectedToWrite), animated: true)
countrySettings[indexPath.row].progress = self.progress.progress
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
downloadTask = nil
progress.setProgress(0.0, animated: true)
if (error != nil) {
print("didCompleteWithError \(error?.localizedDescription ?? "no value")")
}
else {
print("The task finished successfully")
print(downloadCount)
if downloadCount == 1 {
startDownloading()
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
let backgroundSessionConfiguration = URLSessionConfiguration.background(withIdentifier: "backgroundSession" + countryDesignator)
defaultSession = Foundation.URLSession(configuration: backgroundSessionConfiguration, delegate: self, delegateQueue: OperationQueue.main)
progress.setProgress(0.0, animated: false) // This is working correctly
}
}
Upvotes: 1
Views: 334
Reputation: 1473
This is a common problem. Because UITableViewCell
is reuseable
, so you save the cell but the cell will presenting different datasource
when scrolling.
You should not save the cell but record what you are downloading depends on datasource.
func startDownloading () {
guard let indexPath = self.indexPath else { return }
countrySettings[indexPath.row].isEnabled = countrySwitch.isOn
countrySettings[indexPath.row].isDownloading = true
DispatchQueue.main.async {
print(self.countryDesignator) // prints correct Designator
downloadCount += 1
if downloadCount == 1 {
let url = URL(string: "https://www.blablabla.com/" + self.countryDesignator + "_asp.aip")!
countrySettings[indexPath.row].downloadTask = self.defaultSession.downloadTask(with: url)
countrySettings[indexPath.row].downloadTask.resume()
}
}
}
And always change the countryDesignator
to which cell presenting this downloading datasource.
Upvotes: 1