To display each user input I created a table view which displays an array of structs. It works fine, but I'm currently trying to add a headerCell to each entry displaying the date of the input.

Therefore I created another cell called DateCell displaying the date. Additionally I added: func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) to the TableViewController.

My approach is working, but only partially - the DateCell is being displayed but only once with all timelineCells containing the entries underneath. Every time a entry and therefore a timelineCell is being added, the date inside of the DateCell is solely being updated, but I want every timelineCell to have its own DateCell with its own date.

TableViewController

class TimelineViewController: UIViewController {

    @IBOutlet weak var toolbar: UIToolbar!
    @IBOutlet weak var timlineView: UITableView!
    @IBOutlet weak var buttonBack: UIBarButtonItem!

    let defaults = UserDefaults.standard

    var isAsc = false

    override func viewDidLoad() {
        super.viewDidLoad()
        sortArray()
        self.setToolbarInvisible(toolbar: toolbar)
        timlineView.delegate = self
        timlineView.dataSource = self
        setShadow()
    }

    ...

    func sortArray() {
        addDataArray.sort(by: { $1.date < $0.date })
    }

}

extension TimelineViewController: UITableViewDataSource, UITableViewDelegate {

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let rowData = addDataArray[indexPath.row]

        let cell = tableView.dequeueReusableCell(withIdentifier: "TimelineCell") as! TimelineCell

        cell.setDrivenKm(drivenKm: rowData.driven)
        cell.setConsumedL(consumedL: rowData.consumedL)
        cell.setPricePerLiter(pricePerLiter: rowData.pricePerLiter)

        return cell
    }

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let rowData = addDataArray[section]
        let  headerCell = tableView.dequeueReusableCell(withIdentifier: "DateCell") as! DateCell

        headerCell.setDate(date: rowData.date)

        return headerCell
    }

}

HeaderCell

class DateCell: UITableViewCell {

    @IBOutlet weak var dateLabel: UILabel!

    func setDate(date: Date) {
        let date = date
        let formatter = DateFormatter()
        formatter.dateFormat = "dd.MM.yyyy"

        let currentDate = formatter.string(from: date)
        dateLabel.text = currentDate
    }

}

1 Answers

1
Artemiy Shlesberg On Best Solutions

As Sean mentioned in his comment, you can create a section for every entry of addDataArray.

You need to return sections count and change numberOfRows to 1 in each section. Also you need to change the way you retrieve data for you timeline cells, using section instead of row.

So you need to change your UITableViewDelegate methods like this:

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

func numberOfSections(in tableView: UITableView) -> Int {
   return addDataArray.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let rowData = addDataArray[indexPath.section]

    let cell = tableView.dequeueReusableCell(withIdentifier: "TimelineCell") as! TimelineCell

    cell.setDrivenKm(drivenKm: rowData.driven)
    cell.setConsumedL(consumedL: rowData.consumedL)
    cell.setPricePerLiter(pricePerLiter: rowData.pricePerLiter)

    return cell
}

Alternatively you can double your cells count and return both header and items as cells

Then you need to make these changes:


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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

   if indexPath.row % 2 == 0 {
       let rowData = addDataArray[indexPath.row / 2 ]

       let  headerCell = tableView.dequeueReusableCell(withIdentifier: "DateCell") as! DateCell

        headerCell.setDate(date: rowData.date)

        return headerCell
   } else {
        let rowData = addDataArray[indexPath.row / 2]

        let cell = tableView.dequeueReusableCell(withIdentifier: "TimelineCell") as! TimelineCell

        cell.setDrivenKm(drivenKm: rowData.driven)
        cell.setConsumedL(consumedL: rowData.consumedL)
        cell.setPricePerLiter(pricePerLiter: rowData.pricePerLiter)

        return cell
    }
}

I've created a playground to show an example. Check it out here.