UITableView更新错误的单元格

时间:2017-07-23 14:54:46

标签: ios swift uitableview

我有一个Tableview,其中包含同一类的多个单元格。在更改单元格内的开关时,应下载特定文件。

实际行为: 正确的开关正在改变其状态,即使在滚动时它也会被存储,所以这不是问题所在。 countryDesignator在开始下载时是正确的,完成后它也是正确的文件,但是当文件存储时,它使用错误的countryDesignator并且progressBar也是错误的。在这种特殊情况下,点击加拿大将导致文件[..] ca_asp.aip下载并且加拿大单元格中的开关发生变化,但奥地利单元格的progressBar正在移动,存储的文件名为at_asp_aip。

example

代码:

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
  }
}

1 个答案:

答案 0 :(得分:1)

这是一个常见问题。由于UITableViewCellreuseable,因此您保存单元格,但滚动时单元格会显示不同的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()
            }
        }
    }

始终将countryDesignator更改为显示此下载数据源的单元格。