0

don't know if you have encountered this situation, I use the function

func tableView(_ tableView: UITableView, 
     cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
  let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ReusableCell.self), for: indexPath) as! ReusableCell 
  cell.reloadAction = { 
    tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .none) 
  } 
  return cell 
}

to retrieve reusable cell. But now every time I reload the cell, call this function again and it is returning 2 different cells at each call. I draw cells on the storyboard so I don't have the ability to register cells multiple times in the code. If you've ever encountered this case, please help me, I'm very confused :( Thank you very much.

anhhtbk
  • 89
  • 2
  • 12
Trung Hoang
  • 94
  • 11
  • Can you please upload your code for `dequeueReusableCell` ? – steveSarsawa May 06 '19 at 11:29
  • `func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ReusableCell.self), for: indexPath) as! ReusableCell cell.reloadAction = { tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .none) } return cell }` In my cell, I have a button and I will reload this cell whenever I click to it. – Trung Hoang May 06 '19 at 12:03
  • Did you use `Storyboard Identifier` into `main.Storyboard` for `UiTableViewCell`? – steveSarsawa May 06 '19 at 12:05
  • Yes Bhavesh, is it the trouble? – Trung Hoang May 06 '19 at 12:05
  • I realized the difference, when I call `tableView.reloadData()`, it returned the same cell, but when I reload it specifically, for example `tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .none)` it returned 2 cells. Don't know why. – Trung Hoang May 06 '19 at 12:06
  • If you use only one `UITableViewCell` for `IndexPath.section` then Update this Line to `let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellIdentifier", for: indexPath) as! YourTableViewCell` and remove `cell.reloadAction = { tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .none) } return cell }` because `compiler` auto `reload`. – steveSarsawa May 06 '19 at 12:09
  • Bhavesh, in my cell, I have a button, and when I clicked into it, I want the cell be reloaded. – Trung Hoang May 06 '19 at 12:12
  • If you want to `ReloadData` by clicking on`cell_Button` then assign an `tableView.reloadData()` action to `cell_Button` on `cell_ButtonClick` – steveSarsawa May 06 '19 at 12:20
  • In addition how many `numberOfSections` do you want in `tableView()` and how many `numberOfSections` did you actually defined? – steveSarsawa May 06 '19 at 12:25
  • Have you tried reloading the section with `reloadSections(:with:)` instead of reloading the row? – Bram May 06 '19 at 12:25
  • @Craz1k0ek, @Bhavesh, I tried `reloadRows` and `reloadSections` and it returned 2 difference cells each time loaded, only `reloadData()` returned 1 cell as expected. You guys know why? – Trung Hoang May 06 '19 at 12:49

2 Answers2

0

your identifier name seems strange (you don't need to specify its type (String): is that the one you have set in the interface builder pane? I suggest you to check the identifier name and give a try with a code like: withIdentifier: "myCell". Hope this will help.

  • Hi, thank for your answer. I realized the difference, when I call `tableView.reloadData()`, it returned the same cell, but when I reload it specifically, for example `tableView.reloadRows(at: [IndexPath(row: 0, section: 0)], with: .none)` it returned 2 cells. Don't know why. – Trung Hoang May 06 '19 at 12:05
  • @CharlyJapan nothing strange, it's how this method declared. – Daniyar May 06 '19 at 14:07
0

The dequeueReusableCell function is not returning the same cell instance for a given indexPath. It returns a previously allocated cell instance that is currently not used for memory efficiency or a new one if there is none available.

When a reload for a cell is triggered it will not reload the same instance, but jumps into the same cellForRowAt function that will return a reused or new cell.

You could cache all cells yourself and lookup them before requesting new ones. Not memory efficient, but you will have always the same cell instance for an IndexPath. There are corner cases where an own cache make sense. With many, many entries in the data model (lets say a list with 10000 songs) is the recycling of unused (aka not displayed) cells the best way.

How to update the cell then? Best practise to reload cells within a UITableView depends on the source of the event that requires the reload. The two events are either UI (User) related or data model related.

UI/User: You want a reload behaviour from within your cell? Then lets the cell query the data model and update its content. The cell could get its IndexPath as property along with a weak reference to the data model and asking the data model for the newest data. Or you ask the UITableViewDataSource what IndexPath belongs to the cell, to figure out what data relates to it.

Data Model: Why compute updates where are none? A more common and Apple-like way would be an update when the data changed. In this case would the data model know it was changed and trigger an update. Mostly is a reloadData() used, but you could also update all visible cells in a separate thread. For each cell you could use the UITableViewDataSource to tell you what IndexPath it has and decide then if that cell needs to update. Or each cell knows its IndexPath and decides on an update itself it this data is for this cell.

You may notice, there are many ways to update a cell. I don't know what approach suits the needs of your app best, but I think you have now some inspiration how to solve it. Cheers

Helge Becker
  • 3,219
  • 1
  • 20
  • 33