UITableView didSelectRowAtIndexPath: not being called on first tap

Viewed 59665

I'm having an issue with UITableView's didSelectRowAtIndexPath.

My table is setup so that when I select row it initializes a new view controller and pushes it.

The first time I tap any row in the table, the method does not get called. Once I select another row, it begins to work as normal.

I have verified this by setting a breakpoint on didSelectRowAtIndexPath. When adding an NSLog to the method I see that when I select the second row that finally pushes the new view controller, I see two log statements appear in the console at the same time.

Any suggestions?

16 Answers

Any chance you accidentally typed didDeselectRowAtIndexPath?

this issue happens also when you are working with gesture recogniser within a tableView in this case you don't need to remove them, you need only to make sure that your gesture property cancelsTouchesInView = false this is a boolean value affecting whether touches are delivered to a view when a gesture is recognised.

SWIFT 3

If you are working with Swift 3 in a class which isn't a UITableViewController and you are using UITableViewDelegate, then you may need to use the method title:

@objc(tableView:didSelectRowAtIndexPath:) func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){...}

This worked for me, although I have just migrated my project to Swift 3. It's fairly new so this may be fixed later.

If you have set any UITapGestureRecognizer in your class, you can add this line in your didSelectRowAtIndexPath:

[tableView deselectRowAtIndexPath:indexPath animated:NO];

This worked for me.

Swift 4.2

Disabling "Delay Touch Down" in the attributes inspector solved the issue.
After that the clicks are smooth and didSelectRowAt fires immediately.

XCode attributes inspector

In my case I had a UITableView section header with a gesture recognizer. When the header is tapped, it should insert few rows into that section and animate the insertion (like expand/collapse section). First time when expanded and tapped, the didSelectRow delegate method was not fired. For further taps and expand/collapse actions, it was working as expected.

Per answer by @Ayoub Nouri I set cancelsTouchesInView to false, and this resolved the issue. tapGestureRecognizer?.cancelsTouchesInView = false

What worked for me was to start typing "didSelect..." and then let autocorrect fill in the rest. Apparently some detail of my syntax was wonky. As others have said, Use the IDE!!

I had the same issue on my tableView(swift 4.2), it could be fixed with allowsMultipleSelection property on tableView.

If allowsMultipleSelection is set to true the table view selection mechanism will change in a way that by selecting each cell the tableView didSelectRowAtIndexPath: is called for the first time and by selecting the same cell for the second time the tableView didDeselectRowAtIndexPath: is called.

It means that if the number of times a cell tapped are odd (1, 3, 5, ...) then always tableView didSelectRowAtIndexPath: will be called and if the number of times a cell tapped are even (2, 4, 6, ...) then always tableView didDeselectRowAtIndexPath: will be called.

This makes tableView didSelectRowAtIndexPath: function to be called on the third selection for the same cell and so the result is double tap for calling didSelectRowAtIndexPath:!!!

If you want the tableView didSelectRowAtIndexPath: to be called on each selection for a cell then the tableView multiple selection has to be set false, tableView.allowsMultipleSelection = false.

By doing this, every time the cell is tapped tableView didSelectRowAtIndexPath: will be called on table view and by selecting another cell tableView didDeselectRowAtIndexPath: will be called for the cell was selected before and then the tableView didSelectRowAtIndexPath: will be called for the newly selected cell.

    class TableViewController: UITableViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.allowsMultipleSelection = false
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("This will be called for each cell tap")
    }
Related