18

Under certain circumstances, UITableView didSelectRowAtIndexPath is being called twice causing the error Pushing the same view controller instance more than once is not supported.

Here's are the sequence of events:

TableView::didSelectRowAtIndexPath.  
TableView::viewWillDisappear.  
PushedViewController::viewWillAppear.  
TableView::didSelectRowAtIndexPath.  
Error: Pushing the same view controller instance more than once is not supported'  

The only thing worth noting is that the UITableView is loading images asynchronously, but that never calls didSelectRowAtIndexPath. Also, the PushedViewController is reused to avoid having to reload it each time a cell is selected in the UITableView.

Anyone have any idea what may be causing this? Thanks.

Code cracker
  • 3,105
  • 6
  • 37
  • 67
ED.
  • 231
  • 2
  • 4

5 Answers5

32

I'm seeing this problem too, probably one out of a 1000 users gets affected, or less. I сan clearly see two didSelectRowAtIndexPath registering 50 ms one after another. My guess is that it is a bug in iOS - no new taps should be directed to old view once new view-controller has been pushed. Alas, it is likely up to us to write code guarding against this. Here's what I'm thinking:

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
        if (self.navigationController.topViewController != self)        
            return;

    ... do other stuff

    }
DenNukem
  • 8,014
  • 3
  • 40
  • 45
  • 4
    This fix is simple and does the work. btw: on my app I was able to reproduce this issue any time I want. 1. open the app. 2. go to the table view controller which is loading info from internet. 3. tap any row like crazy while its loading. 4. several DidSelect are triggered and the detailViewController is pushed more than once – AmitP Sep 05 '13 at 10:34
  • 1
    I was having this problem, specificially while performing a segue manually in didSelectRowAtIndexPath. I did some testing to make sure that this wasn't going to preempt legitimate cell selections, and lo and behold, it works like a charm! – averydev Apr 06 '14 at 17:24
1

if you already created Storyboard Segue don't call;

[self performSegueWithIdentifier:@"TYPE" sender:self];

in this method;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

ali ozkara
  • 5,425
  • 2
  • 27
  • 24
1

Disable user interaction after the first "didSelectRow". It's possible for multiple taps to "stack up" during the transition.

It usually takes someone with amazing dexterity in their fingers to get this behavior, but still.

Steven Kramer
  • 8,473
  • 2
  • 37
  • 43
  • [someone with amazing dexterity in their fingers to get this behavior]. You're right, but it's happening. Does this mean you've seen this before? Could it be a bug in iOS? – ED. Apr 17 '11 at 02:28
  • 9
    someone with amazing dexterity like a damn tester – Adam Waite Oct 01 '13 at 14:35
  • Adam, yeah, that's right. @ED. : whether it's a bug in iOS or not, I can't tell. Definitely seen in the wild too as recently as iOS 7 if I'm not mistaken. – Steven Kramer Oct 02 '13 at 13:18
  • you can recreate this easily by hitting a break point anywhere to freeze the app (or maybe just press pause) then double tapping the cell and then continuing. Put another break point at didSelectRow and you'll see it hit twice. – malhal Apr 21 '15 at 23:22
0

This occurs because of the segue you are using inside the didSelectRowAtIndexPath method. Ensure that this segue is created by ctrl dragging from the view button on top of the source view controller to destination view controller. The error occurs when you create the segue by ctrl dragging from the table view cell to destination view controller. You do not need to change any of you code. Just delete the segue and create it in the correct way. Hope this solves your problem, if I got the question right.

shim
  • 9,289
  • 12
  • 69
  • 108
Arun Reddy
  • 3,443
  • 1
  • 21
  • 16
0

Swift 5

In my case also helped to update the cells instead of this code:

tableView.reloadRows(at: [indexPath], with: .automatic)

to use this:

tableView.reloadData()
J A S K I E R
  • 1,976
  • 3
  • 24
  • 42