Search code examples
iosswiftuitableviewxib

Duplicating rows within cell footer view of tableView swift


I have two Xib's in tableview, One is cell custom UITableViewCell Xib and second is UIView custom view xib (which is footerView). On clicking date cell it shows me appointment list. (image attached for reference). I am getting data from SQLite and then records append to model.

  • Issue is for unknown reason it duplicates the appointment list in footerView. First when it load data its fine. When I move/scorll tableView or come back to same page it shows duplicate.
  • I used for loop displaying appointment list record in footerView. (in cellForRowAt)
  • I have checked but there is no duplicate data append in array model var downloadAppData: [DownloadDisplay] = []

How to avoid duplicating footer view rows in cell TableView?

deceleration: var downloadAppData: [DownloadDisplay] = []

Model:

struct DownloadDisplay : Codable {
    var date: Int64?
    var appointments: [Appointment]?
    var progress: Double?
    var isFinished: Bool?
}

struct Appointment : Codable {

    let appointmentHour : String?
    let backgroundColorDark : String?
    let backgroundColorLight : String?
    let controlHour : String?
    let date : String?
    let id : Int?
    let isProjectManual : Bool?
    let projectDistrict : String?
    let projectFirmName : String?
    let projectName : String?
    let projectType : String?
    let subTitle : String?
    let warmingType : String?
}

TableView:

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "DownloadEntryViewCell", for: indexPath) as! DownloadEntryViewCell
        let dic = downloadAppData[indexPath.row]
        let content = datasource[indexPath.row]


        let appDate = Date(milliseconds: dic.date ?? 0)        
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier: "tr_TR_POSIX")
        dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
        dateFormatter.dateFormat = "dd MMMM yyyy EEEE"
        let convertDate = dateFormatter.string(from: appDate)

        cell.fileNameLabel.text = "\(convertDate)" + " Randevuları"

        var stackHeight:CGFloat = 0.0

        // footer view xib. 
        for i in (dic.appointments)! {
            let child_view = Bundle.main.loadNibNamed("FooterView", owner: self, options: nil)?.first as! FooterView
            child_view.projName.text = "\(i.projectName ?? "")" + "  " + "\(i.subTitle ?? "")"
            cell.stackViewFooter.addArrangedSubview(child_view)
            stackHeight = stackHeight + 33.0
        }


        if content.expanded == false {

            cell.rightView.backgroundColor = ("#556f7b").toColor()
            cell.fileNameLabel.textColor = ("#eceff1").toColor()
            cell.progressLabel.textColor = ("#eceff1").toColor()
            cell.individualProgress.frame = CGRect(x: 0, y: 69, width: 360, height: 2)
            cell.individualProgress.progress = 0
            cell.individualProgress.backgroundColor = ("#cfd8dc").toColor()

       }

        return cell
    }

Solution

  • Cells are reused. That means anything you do to a cell will still be in effect when that cell is reused.

    In your case, you are adding (more) subviews to a stackView each time cellForRowAt is called.

    You could either:

    A) edit your cell class and implement prepareForReuse(), where you would remove any existing subviews from the stackView

    override func prepareForReuse() {
        self.stackViewFooter.subviews.forEach {
            $0.removeFromSuperview()
        }
    }
    

    or

    B) remove the subviews before adding new ones in cellForRowAt

        // first
        cell.stackViewFooter.subviews.forEach {
            $0.removeFromSuperview()
        }
    
        // then
        for i in (dic.appointments)! {
            ...
            cell.stackViewFooter.addArrangedSubview(child_view)
        }