0

I have developed an iOS app it has couple of tableviews. It works fine if I did not scroll, if i scroll tableview data inside cells data is changing pls make me perfect here. Here is the code below for first table which will have UISwitch and text.enter image description here For reference pls watch video: https://drive.google.com/open?id=1hVHnAyGnQFrhvzLSoJjeMzG6wlfxoURm

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
   if let d = self.data {
       return d.count
   }
   return  0

}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCell(withIdentifier: "cell")

    if let _ = cell {} else {
        cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
    }
    if let d = self.data {
        cell?.textLabel?.text = d[indexPath.row]
        let switchView = UISwitch(frame: .zero)
        switchView.setOn(self.isFolderIsAdded(folderName: d[indexPath.row]), animated: true)
        switchView.tag = indexPath.row // for detect which row switch Changed
        switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
        cell?.accessoryView = switchView

    }
    return cell!
}

func isFolderIsAdded(folderName:String) -> Bool{
    for   val in listOfSelectedFolder{
        if(folderName == val ){
            return true
        }
    }
    return false;
}

@objc func switchChanged(_ sender : UISwitch!){
    if let d = self.data {
        if(sender.isOn){
            self.delegate?.selectedSubFolder(name: d[sender.tag])
           } else {
            self.delegate?.deleteFilesFromFolder(folderName: d[sender.tag])
        }
    }
}

Here is the second table code which will have image view and text. I created custom cell named TableViewCell enter image description here. For reference pls watch video: https://drive.google.com/open?id=11snH5_henOadVCVqS9bL5SZRjcZF3vEU

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableViewContent.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! TableViewCell
    if let _ = contentModel[self.currentMode]{
        tempArr1 = appendFolderName(files: contentModel[self.currentMode]!, name: self.currentMode)!

    }
    if indexPath.row < tempArr1.count {
        cell.setupCellData(text: tempArr1[indexPath.row])
    }else{
        if let res = self.getFilesFromSubFolder(contentName: self.currentMode, folderName: self.SelectedFolder) {
            cell.setupCellData(text: res[indexPath.row - tempArr1.count] )

        }
    }
    let bgColorView = UIView()
    bgColorView.backgroundColor = UIColor.gray
    cell.selectedBackgroundView = bgColorView
    return cell
}

func setupCellData(text:String) {
    let temarr = text.components(separatedBy: "@")
    let str =  temarr.last?.capitalized
    let strq = temarr.first?.lowercased()
    let newstr = strq?.components(separatedBy: "-")
    let val = newstr?.last
    let content = val!.lowercased() + "@" +  str!
    self.ContentLabel.text = content
    if ((self.ContentLabel.text?.contains("pps"))!||(self.ContentLabel.text?.contains("pptx"))!||(self.ContentLabel.text?.contains("ppt"))!){
        imageData.image = #imageLiteral(resourceName: "table_Content_ppt")
    }else if ((self.ContentLabel.text?.contains("mp4"))! || (self.ContentLabel.text?.contains("mp3"))!){
        imageData.image = #imageLiteral(resourceName: "table_Content")
    }else if (self.ContentLabel.text?.contains("pdf"))!{
        imageData.image = #imageLiteral(resourceName: "pdf_content")
    }else if (self.ContentLabel.text?.contains("url"))!{
        imageData.image = #imageLiteral(resourceName: "url_content")
    }else if (self.ContentLabel.text?.contains("exe"))!{
        imageData.image = #imageLiteral(resourceName: "application_content")
    }else if (self.ContentLabel.text?.contains("doc"))!{
        imageData.image = #imageLiteral(resourceName: "word_content")
    }else if (self.ContentLabel.text?.contains("bat"))!{
        imageData.image = #imageLiteral(resourceName: "cmd")
    }
    else if (self.ContentLabel.text?.contains("lnk"))!{
        imageData.image = #imageLiteral(resourceName: "cmd")
    }
    else if ((self.ContentLabel.text?.contains("png"))! || (self.ContentLabel.text?.contains("jpg"))! || (self.ContentLabel.text?.contains("jpeg"))! || (self.ContentLabel.text?.contains("psd"))! || (self.ContentLabel.text?.contains("tiff"))! || (self.ContentLabel.text?.contains("gif"))!) {

        imageData.image = #imageLiteral(resourceName: "img")

    }else{
        imageData.image = nil

    }

}

I have added prepareForReuse()method in tableview cell class but still result is same content is changed after scroll.

    override func prepareForReuse() {
    super.prepareForReuse()
    // Clear all content based views and their actions here
     imageData.image = nil
    ContentLabel.text = ""
}
  • 2
    You need to clear the reused cell content before adding new data on it. – Leo Dabus Dec 03 '19 at 11:18
  • Btw you should update your Xcode to the current version. – Leo Dabus Dec 03 '19 at 11:20
  • @LeoDabus Pls help me on that I'm new to iOS. Thanks –  Dec 03 '19 at 11:20
  • Just clear it. If it is an image set it to nil, and so on after you dequeue your cell – Leo Dabus Dec 03 '19 at 11:22
  • I have to clear in cellForRowAt indexPath?? pls give some more idea in which case I need to clear . For example UISwitch+Text first table scroll pls post your answer. Thanks –  Dec 03 '19 at 11:26
  • Yes once you get a reused cell there just clear it below dequeueReusableCell – Leo Dabus Dec 03 '19 at 11:28
  • Not related to your question but you should use the fileURL Type identifier resourceValue to check your file type. https://stackoverflow.com/a/34772517/2303865 – Leo Dabus Dec 03 '19 at 11:35
  • Check the link above on how to get your file localized name as well – Leo Dabus Dec 03 '19 at 11:36
  • I added at the end of my question please check it. –  Dec 03 '19 at 11:40
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/203524/discussion-between-rahul-and-leo-dabus). –  Dec 03 '19 at 11:46
  • erase your cell content unconditionally – Leo Dabus Dec 03 '19 at 11:49
  • Unrelated but why is the data source array declared as optional? You can get rid of a lot of unnecessary `if let` expressions if you declare the array as non-optional. – vadian Dec 03 '19 at 12:54
  • Okay I will remove if let statements but as others said not able to implement resetting cell data after scroll pls help. –  Dec 03 '19 at 12:58

3 Answers3

1

You have to update the listOfSelectedFolder array in switchChanged.

Assuming self.data will be declared as non-optional change the method to

@objc func switchChanged(_ sender : UISwitch){
    let folderName = self.data[sender.tag]
    if sender.isOn {
        listOfSelectedFolder.append(folderName)
        self.delegate?.selectedSubFolder(name: folderName)
    } else {
       if let index = listOfSelectedFolder.index(of: folderName) {
          listOfSelectedFolder.remove(at: index)
       }
       self.delegate?.deleteFilesFromFolder(folderName: folderName)
    }
}

The other methods can be optimized

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.data.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
    let folderName = self.data[indexPath.row]
    cell.textLabel?.text = folderName
    let switchView = UISwitch(frame: .zero)
    switchView.setOn(self.isFolderAdded(folderName: folderName), animated: true)
    switchView.tag = indexPath.row // for detect which row switch Changed
    switchView.addTarget(self, action: #selector(switchChanged), for: .valueChanged)
    cell.accessoryView = switchView
    return cell
}

func isFolderAdded(folderName: String) -> Bool{
    return listOfSelectedFolder.contains(folderName)
}

However it's highly recommended to use a custom struct as data model and add a isSelected property. And declare listOfSelectedFolder as a Set.

vadian
  • 274,689
  • 30
  • 353
  • 361
0

Put this in your cell class

    override func prepareForReuse() {
        super.prepareForReuse()
        // Clear all content based views and their actions here
    }
Sebastian
  • 44
  • 1
  • 2
  • I added prepareforreuse in cell class. I have one image view and label how do I reset it: imageData = nil ContentLabel = nil. IS this correct? –  Dec 03 '19 at 12:18
  • no, you should do this: imageData.image = nil & contentLabel.text = "" – Sebastian Dec 03 '19 at 12:25
  • **For performance reasons, you should only reset attributes of the cell that are not related to content, for example, alpha, editing, and selection state. The table view's delegate in tableView(_:cellForRowAt:) should always reset all content when reusing a cell** https://developer.apple.com/documentation/uikit/uitableviewcell/1623223-prepareforreuse – Leo Dabus Dec 03 '19 at 12:32
  • It's wrong, anything may be different in cells most reset. something like layout or color or... that is same in all cells doesn't need to reset. read this: https://fluffy.es/solve-duplicated-cells/ – Sebastian Dec 03 '19 at 12:41
  • I added prepareForReuse() in cell class but still content is changing after scroll pls check I added code at the end of my question. –  Dec 03 '19 at 12:50
  • it's not logical you wrote? why did you do it? if indexPath.row < tempArr1.count { cell.setupCellData(text: tempArr1[indexPath.row]) }else{ if let res = self.getFilesFromSubFolder(contentName: self.currentMode, folderName: self.SelectedFolder) { cell.setupCellData(text: res[indexPath.row - tempArr1.count] ) } } – Sebastian Dec 03 '19 at 13:00
  • The problem is not to clear the content, the problem is that the data model is not updated properly in `switchChanged`. Implementing `prepareForReuse ` is pointless in this case. – vadian Dec 03 '19 at 13:10
  • @vadian Rahul said: It works fine if I did not scroll, if i scroll tableview data inside cells data is changing. Means scrolled cell views do not update avoid its data. – Sebastian Dec 03 '19 at 13:18
  • Yes because `cellForRowAt` is called again and `isFolderIsAdded` returns the wrong value if it's not being updated in the switch action. – vadian Dec 03 '19 at 13:22
  • Of course the array most update on changes, you right. anyway table views with dynamic contents needs to prepareForReuse – Sebastian Dec 03 '19 at 13:30
0

I also experienced the same issue before and I tried to add layoutIfNeeded() inside the cellForRowAt and it solved the problem.

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCell(withIdentifier: "cell")

    if let _ = cell {} else {
        cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
    }
    if let d = self.data {
        cell?.textLabel?.text = d[indexPath.row]
        let switchView = UISwitch(frame: .zero)
        switchView.setOn(self.isFolderIsAdded(folderName: d[indexPath.row]), animated: true)
        switchView.tag = indexPath.row // for detect which row switch Changed
        switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
        cell?.accessoryView = switchView
cell?.layoutIfNeeded() <--- Add this

    }
    return cell!
}
vidalbenjoe
  • 921
  • 13
  • 37