Attempted to dequeue multiple cells for the same index path, which is not allowed
Asked Answered
Z

7

11

I have a very simple UITableView that has worked just fine since iOS6....I have recently tried to make a new build going from iOS10-iOS11 and now I am getting this new NSInternalConsistency Exception that I have never seen before, it literally came out of left field with the new iOS build....

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempted to dequeue multiple cells for the same index path, which is not allowed. If you really need to dequeue more cells than the table view is requesting, use the -dequeueReusableCellWithIdentifier: method (without an index path). Cell identifier: WorkOrderCell, index path: {length = 2, path = 0 - 0}'

I have reviewed numerous tutorials and I feel like there is nothing exceptionally wrong with this code..in fact normal grid load works fine, here is my code:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"WorkOrderCell" forIndexPath:indexPath];



    // Configure the cell...  do some work, return it



    return cell;
}

Has anyone else experienced this issue and what have you done to resolve it?

I should be a bit more specific, the normal UITableView does load fine, this specific issues is that I have a SearchBar, and when the user types into the search, I am filtering the results and displaying a results grid:

//Start Search/Filter Code
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
    NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"Job contains[cd] %@ or Address contains[cd] %@ or WorkOrderId contains[cd] %@ or Supervisor contains[cd] %@", searchText, searchText, searchText, searchText];
    self.filteredWorkOrders = [self.workOrders filteredArrayUsingPredicate:resultPredicate];
}


-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    [self filterContentForSearchText:searchString
                               scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
                                      objectAtIndex:[self.searchDisplayController.searchBar
                                                     selectedScopeButtonIndex]]];

    return YES;
}

The filter code itself works fine, it's just that it triggers the UITableView delegates to fire, which starts dequeuing cells (which should be empty right in the search results grid??)

In any event I could use some help with this one please.....

Zoba answered 9/12, 2017 at 2:28 Comment(2)
Do you manually call cellForRowAtIndexPath somewhere in your code? Like [self.tableView cellForRowAtIndexPath:]Marcus
Hey Cookies, nope I double checked, it's really setup with standard delegates nothing special no manual calls, it's really strange, just started happening with latest Xcode updatesZoba
H
11

Don't use self.tableView in your cellForRowAtIndexPath method (or any of the other data source and delegate methods). Use the tableView parameter.

This is really important when your data source and delegate methods are being used for more than one table view.

Hallucinosis answered 9/12, 2017 at 5:16 Comment(3)
Wow this was a humongous chore...... unfortunately your tip didn't solve it, but it got me thinking, and what I ended up doing was this:: fork the dequeue based on search/normal grid Bid *bid; if (tableView == self.searchDisplayController.searchResultsTableView) { cell = [_tableView dequeueReusableCellWithIdentifier:@"BidCell"]; bid = _filteredBids[indexPath.row]; } else { cell = [_tableView dequeueReusableCellWithIdentifier:@"BidCell" forIndexPath:indexPath]; bid = _bids[indexPath.row]; }Zoba
You only need one call to dequeueReusableCell if you call it on the tableView parameter. You are still using the same _tableView (which is the direct instance variable for the self.tableView property.Hallucinosis
I need the prototypes so I can't dequeue the generic, also I am using the same cell prototype for both the tableView and the searchResultsTableView....I had to convert it from a UITableViewController to a UIViewController and link the outlet manually, previously with iOS6 I could just use the UITableViewController and everything worked fine, I think they introduced something new with iOS11 that broke this de facto UITableViewController functionality..... I never had to link outlets before and I have 10 grids...., I realize now it's better practice to do so, but just saying i never had toZoba
E
12

Another possibility is that you may be accidentally using dequeueReusableCell method more than once within the same tableView.

For example you may also be using it in didSelectRowAt or didEndDisplaying cell by mistake.

Environmentalist answered 22/5, 2018 at 12:36 Comment(1)
I created a cell multiple times. one is default and another inside if conditions. Tried with creating empty cell let cell: UITableViewCell = UITableViewCell() in cellForRowAt indexPath: method . it workedDilatory
H
11

Don't use self.tableView in your cellForRowAtIndexPath method (or any of the other data source and delegate methods). Use the tableView parameter.

This is really important when your data source and delegate methods are being used for more than one table view.

Hallucinosis answered 9/12, 2017 at 5:16 Comment(3)
Wow this was a humongous chore...... unfortunately your tip didn't solve it, but it got me thinking, and what I ended up doing was this:: fork the dequeue based on search/normal grid Bid *bid; if (tableView == self.searchDisplayController.searchResultsTableView) { cell = [_tableView dequeueReusableCellWithIdentifier:@"BidCell"]; bid = _filteredBids[indexPath.row]; } else { cell = [_tableView dequeueReusableCellWithIdentifier:@"BidCell" forIndexPath:indexPath]; bid = _bids[indexPath.row]; }Zoba
You only need one call to dequeueReusableCell if you call it on the tableView parameter. You are still using the same _tableView (which is the direct instance variable for the self.tableView property.Hallucinosis
I need the prototypes so I can't dequeue the generic, also I am using the same cell prototype for both the tableView and the searchResultsTableView....I had to convert it from a UITableViewController to a UIViewController and link the outlet manually, previously with iOS6 I could just use the UITableViewController and everything worked fine, I think they introduced something new with iOS11 that broke this de facto UITableViewController functionality..... I never had to link outlets before and I have 10 grids...., I realize now it's better practice to do so, but just saying i never had toZoba
T
5

As the warning message said, just use

dequeueReusableCell(withIdentifier: "YourIdentifierCellHere")

Without

for: indexPath
Telling answered 2/4, 2021 at 5:6 Comment(0)
W
3

In my case i was calling "cellForRowAt indexPath" while the table was reloading because of another parallel process. Then i implemented flag and delayed the "cellForRowAt indexPath" while "cellForRowAt indexPath" method is working. So it wont be load in parallel for same cell

Wantage answered 15/6, 2018 at 7:58 Comment(0)
A
2

Check have you initiated same table view cell more than once.

In my case i have initiating table view cell twice as below:

let cell = tableView.dequeueReusableCell(withIdentifier: "SampleTableViewCell", for: indexPath) as! SampleTableViewCell
cell.label.text = "Testing"
If name != "" {
   let cell = tableView.dequeueReusableCell(withIdentifier: "SampleTableViewCell", for: indexPath) as! SampleTableViewCell
   cell.userName.text = name
}

Then i have removed the second initiation and updated the code as below:

let cell = tableView.dequeueReusableCell(withIdentifier: "SampleTableViewCell", for: indexPath) as! SampleTableViewCell
cell.label.text = "Testing"
If name != "" {
   cell.userName.text = name
}
Alius answered 18/1, 2023 at 9:18 Comment(0)
B
0

My issue was missing a return in cellForRowAt.

I was missing a return inside if-statement, so it tried to create two different cells on the first index:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if indexPath.row == 0 {
        let cell = table.dequeueReusableCell(withIdentifier: "FirstIdentifier", for: indexPath) as! FirstCell
    }
    let cell = table.dequeueReusableCell(withIdentifier: "AnotherIdentifier", for: indexPath) as! AnotherCell
    return cell
}
Bain answered 7/3 at 23:29 Comment(2)
Using an else would help make the code clearer.Salerno
my statements were more complex, this is just an example. @SalernoBain
E
0

In my case ... I tried to call the dequeue method and failed each time because index paths started subtracting the values after greater values of indexPath were selected.

error line:

let cell = tableView.dequeueReusableCell(withIdentifier: "SampleTableViewCell", for: indexPath) as! SampleTableViewCell

So the idea is to call the same cell, but from the system method didSelect etc. However, we will call cellForRow...

solution:

let cell = myNamedTableView.cellForRow(at: indexPath) as! TableViewCell
Ermey answered 27/7 at 18:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.