indexPath.row Issues - Cells not Rendering

I have an app that lets you add items to your personal search index from a master index.

When I add an item to an index from the master view, the new item appears as expected at the top of the personal collection table view, but the table view seems to “push” cells at the bottom out and then displays a blank cell where the lowest item should have been. I think it has something to do with cells being recycled. For the blank items, I’m getting nil when I print the value of hit at the indexPath.row:

hit = hitsSource?.hit(atIndex: indexPath.row) 

See this example. (by the way, hitsSource = HitsInteractor<Model>).

As you can see, there are three blank cells, one for each of the three items I added to the personal “collection” index. At the very top of the screen you see one of the newly added items on top of it. Those seem to be pushing the others out.

When I delete the recently added items and call searcher.search() again, the top cell is deleted and the bottom cell displays correctly.

I’ve tried to use reloadData(), but it doesn’t solve the problem. Any ideas how to prevent this from happening? Might it be some sort of simple miscalculation with my setup? Do I need to modify my UITableViewController/HitsController?

What I think is going on:

tableView knows that it should display x number of rows based on hitsSource?.numberOfHits(). It’s doing that correctly, and when I add an item, the console output indicates a correct number of rows at the correct indexPath. However, the last row (or rows if I have added multiple items) displays as a blank cell. Here is where I think the problem resides:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
	  guard let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as? CollectionCell else {
		return .init()
	  }
		let hit = hitsSource?.hit(atIndex: indexPath.row)
		 // do stuff with data, assign to cell UI elements, etc.
  }

Let’s say I fire up the program and there are 3 items in the index. I add a fourth item and call searcher.search() again. The table knows to add a row, since numberOfHits() returns 4. As it’s populating the cells and gets to the fourth row, hit in the above snippet is equal to nil, and thus I get a blank cell.

How can I tell the controller to keep going and render that last cell properly?

Update/Solution (Kind of)

This is kind of a hacky fix, but when I run the code to add a new item, I do this:

var currentSearch = searcher.query ?? ""
searcher.query = currentSearch + " "
searcher.search()

This will take whatever was in the searcher query, add a blank space to it, and run the search again. It runs a fresh search and recalculates the hits. Solves my problem, but probably not best practice.

Hi @yulelogsean,

The issue here is related to HitsInteractor page caching mechanism. It is not adapted to work with dynamically updated results, resulting in inconsistencies you described. If you want to update the results manually, you firstly have to call notifyQueryChanged() method of your HitsInteractor that clears its caches (it is called when you apply the hack you described above). Then you can call searcher.search() method to fill the clean HitsInteractor with updated results.

1 Like