Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView push segue triggered multiple times

I came across a strange bug in my app:

The setup

A simple Master-Detail app, iPhone style (ie. no split view, no popover, just a navigation controller, a table view controller, and a view controller).

enter image description here

The bug

  1. Touch a "background" part of the table view (the darker grey parts on my screenshot) like a section header or footer.
  2. While keeping your finger on the screen, touch a cell multiple times.
  3. Release all fingers. The "detail" view will pushed normally, but when touching the back button, you will find that the detail view was stacked as many times as you touched the cell at step 2.

enter image description here

You can also touch multiple cells at step 2 and their destination views will be stacked in the correct order :)

Reproduce it

I was able to reproduce the bug with a clean, freshly created app, and on the last release of the Twitter app for iPhone (by touching the "Loading" label with finger #1 and touching a tweet multiple times).

However, I could not trigger the same behaviour in the Settings app, under the "General" tab (which is a grouped table view).

The bug was reproduced on iOS 6.0 and 6.1. I don't have devices with older versions to test.

Question

Is this a known trick when creating navigation/table view based apps and if so is there a solution to prevent this (weird) behavior ? Or is this an iOS bug (and if so, is it already known from Apple) ?

like image 248
Guillaume Algis Avatar asked Oct 04 '22 19:10

Guillaume Algis


1 Answers

A possible stop-gap measure you could use is to implement

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender

And use a boolean flag or something to indicate that you are currently trying to execute that segue. ex:

BOOL doingSegue = NO;

-(void) viewWillAppear
{

    doingSegue = NO;
}

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{

    if ( [identifier isEqualToString:@"MySegueIdentifier"] )
    {
        if ( doingSegue )
        {
            return NO;
        }
        else
        {
            doingSegue = YES;
            return YES;
        }
    }
    return YES;
}

Swift Version

var doingSegue = false

override func viewWillAppear(_ animated: Bool) {
    doingSegue = false
}

override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
    if identifier == "MySegueIdentifier" {
        if doingSegue {
            return false
        }
        else {
            doingSegue = true
            return true
        }
    }
    return true
}
like image 115
Dan F Avatar answered Oct 13 '22 12:10

Dan F