mahan
mahan

Reputation: 15035

tableView.reloadData() adds a UIView that it should not do

I a have a modal with optional properties. And as you may have guessed, I only add a UIView for non-optional properties. In the following code, dueDate is optional. The first one has due-date and the second does not.

let london = Task( name: "Hello from London",
                     createdDate: Date(),
                     isCompleted: false,
                     dueDate: Date())

let madrid = Task( name: "hola desde madrid",
                     createdDate: Date(),
                     isCompleted: false)

Data source method that inserts cells.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.identifier, for: indexPath) as! TableViewCell

    if  let _ = tasks[indexPath.row].dueDate {
        cell.textLabel?.text = "Due Date"
    }

    return cell
}

When I open the app, it works as I expect. Only the first cell has Due Date. I expect it so since it is only the first task that has due-date. However, when I remove the first cell(see code below) and reload date, Due Date is added in the second cell too. I do not understand it. I expect that it should not be added since the second task does not have due-date

Delegate method that removes cells

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    let remove = UITableViewRowAction(style: .normal, title: "Remove") { action, index in
        let task =  self.tasks.remove(at: indexPath.row)
        print(task.name) //
        tableView.reloadData()
    }
    remove.backgroundColor = .red

    return [remove]
}

What I do wrong? How can I fix this issue?


If you need more info, please just ask.

Upvotes: 0

Views: 38

Answers (2)

Shehata Gamal
Shehata Gamal

Reputation: 100551

It's because of dequeuing , so replace it with

cell.textLabel?.text = tasks[indexPath.row].dueDate != nil ? "London" : ""

when you delete the first cell , it's get dequeued by the second cell so you see the second cell configured with attributes of the removed one , so inside cellForRowAt you need to make sure you set code every run

Upvotes: 1

Connor Neville
Connor Neville

Reputation: 7361

Look at your cellForRow:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.identifier, for: indexPath) as! TableViewCell

    if let _ = tasks[indexPath.row].dueDate {
        cell.textLabel?.text = "London"
    }

    return cell
}

Now, when you remove a cell, you call reloadData on a cell that previously had a due date, but now does not. Since the if doesn't get executed, you're not doing anything with the cell. Add an else case.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.identifier, for: indexPath) as! TableViewCell

    if let _ = tasks[indexPath.row].dueDate {
        cell.textLabel?.text = "London"
    }
    else {
        cell.textLabel?.text = nil
    }

    return cell
}

Upvotes: 1

Related Questions