303
votes

I'm writing an iOS app with a table view inside a tab view. In my UITableViewController, I implemented -tableView:didSelectRowAtIndexPath:, but when I select a row at runtime, the method isn't being called. The table view is being populated though, so I know that other tableView methods in my controller are being called.

Does anyone have any ideas what I may have screwed up to make this happen?

30
also you may have a gestureRecognizer on top of the UITableView that absorbs the selection .. (one of the possibilities)M.Othman
Be careful if the table view is being populate, it means the DataSource is well set. The selection is part of the Delegate methods. So maybe the DataSource is well set but not the Delegate !Thomas Besnehard
Hi M.Othman, your comment is exactly what was wrong with my own issue. Do you know how to get gestureRecognizer working 'with' the UITableView?yhl
I notice that if I tap and hold, the tap eventually calls -didSelectRowAtIndexPath. I figured out hat's because I have a tap gesture recognizer on the tableview and the gesture has to fail first before receiving the touch. Though it's weird the table selection animation is not affected by the gesture recognizer.Hlung
I had the same problem here and had the fortunate opportunity to learn that you cannot have a gestureRecognizer on top of the UITableView. Thanks M. Othman!vnchopra

30 Answers

98
votes

It sounds like perhaps the class is not the UITableViewDelegate for that table view, though UITableViewController is supposed to set that automatically.

Any chance you reset the delegate to some other class?

535
votes

Just in case someone made the same stupid mistake as I did:

Check out if the method name of what you expect of being didSelect may accidentally be gotten didDeselect in some way. It took about two hours for me to find out ...

515
votes

Another thing that might lead to the issue is not selected selection kind:

UITableView selection kind

Should be Single Selection for normal selection, should not be No Selection.

To do this programmatically, do:

tableView.allowsSelection = YES
301
votes

Another possibility is that a UITapGestureRecognizer could be eating the events, as was the case here: https://stackoverflow.com/a/9248827/214070

I didn't suspect this cause, because the table cells would still highlight blue as if the taps were getting through.

151
votes

All good answers, but there's one more to look out for...

(Particularly when creating a UITableView programmatically)

Make sure the tableView can respond to selection by setting [tableView setAllowsSelection:YES]; or removing any line that sets it to NO.

94
votes

If the problem arise with UITapGestureRecognizer you can fix this:

  • in Storyboard:

enter image description here

in code with Objective-C:

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard)]; 
[self.view addGestureRecognizer:tap];

[tap setCancelsTouchesInView:NO];

in code with Swift:

let tap = UITapGestureRecognizer(target: self, action:Selector("dismissKeyboard"))
view.addGestureRecognizer(tap)

tap.cancelsTouchesInView = false
68
votes

I have encountered two things in this situations.

  1. You may have forgot to implement UITableViewDelegate protocol, or there's no delegation outlet between your class and your table view.

  2. You might have a UIView inside your row that is a first responder and takes your clicks away. Say a UIButton or something similar.

45
votes

I have had the same problem. And it was hard to find. But somewhere in my code was this:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    return nil;
}

It must be return indexPath, else -tableView:didSelectRowAtIndexPath: is not being called.

38
votes

If you added a gestureRecognizer on top of the UITableView, didSelectRowAtIndexPath will not get called.

So you need to use gestureRecognizer delegate method to avoid touch in particular view.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if ([touch.view isDescendantOfView:YourTable]) {
        return NO;
    }
    return YES;
}
30
votes

I've ran into a problem where after months of not looking at my code I forgot that I implemented the following method due to some requirements which were not necessary

- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath  *)indexPath{
    return NO;
}

It should be returning YES for a row in order to make it selected.

24
votes

YOU MUST select these options

enter image description here

but if you want to make UITableViewnot highlighted on clicking then you should make changes in UITableViewCell properties.

Choose None option for Selection just like below

enter image description here

21
votes

I had put a UITapGestureRecognizer on my table view to dismiss the keyboard which prevented didSelectRowAtIndexPath: from being called. Hope it helps someone.

19
votes

In case you have the same problem as me: Apparently, this method won't be called if your tableView is in edit mode. You have to set allowsSelectionDuringEditing to true.

Via this question: When editing, `UITableView` does not call didSelectRowAtIndexPath ??

19
votes

I had the same problem,

The reason was using of UITapGestureRecognizer. I wanted the keyboard to dismiss when I tapped anywhere else. I realized that this overrides all tap actions, that is why, didSelectRowAtIndexPath function did not called.

When I comment the rows related with UITapGestureRecognizer, it works. Moreover you can check in the function of UITapGestureRecognizer selector if the tapped is UITableViewCell or not.

15
votes

In my case, didSelctRowAtIndexPath not calling is due to that I have selected none in the Selection property of tableView, set to single selection solved my problem

enter image description here

11
votes

For Xcode 6.4, Swift 1.2 . The selection "tag" had been changed in IB. I don't know how and why. Setting it to "Single Selection" made my table view cells selectable again. enter image description here

10
votes

Even though another answer has been accepted, I'll add one more possible problem and solution for people who observe this issue:

If you have automatic reference counting (ARC) turned on, you may find that even after assigning your controller as a delegate of the view, the view's messages to the controller are not being received because ARC is deleting the controller. Apparently the UITableView's delegate pointer does not count as a reference for the ARC, so if that is the only reference to it, the controller will be dealloc'd. You can verify whether or not this is happening by implementing the dealloc method on the controller and setting a breakpoint or NSLog call there.

The solution is to keep track of the controller with a strong reference somewhere else, until you are sure you won't need it anymore.

10
votes

Remember to set the datasource and delegate in the viewDidLoad method as follows:

[self.tableView setDelegate:self];

[self.tableView setDataSource:self];
9
votes

My problem was none of the above. And so lame. But I thought I would list it here in case it helps someone.

I have a tableViewController that is my "base" controller and then I create subclasses of this controller. I was writing all my code in the tableView:didSelectRowAtIndexPath routine in the "base" class. Completely forgetting that by default this routine had also been created (albeit with no code that did anything) in all of my subclasses as well. So when I ran my app, it ran the subclass version of the code, did nothing, and made me sad. So of course, once I removed the routine from the subclasses, it used mt "base" class routine and I'm in business.

I know. Don't laugh. But maybe this will save someone the hour I lost...

9
votes

Giving my 2 cents on this.

I had a Custom UITableViewCell and there was a button covering the whole cell, so when the touch happened, the button was selected and not the cell.

Either remove the button or in my case, I set User Interation Enable to false on the button, that way the cell was the one selected.

8
votes

If you read this, so still doesn't solve the problem.

I have custom cell, where checkbox "User Interaction Enabled" was disable. So, I Just switch on it. Good luck.

7
votes

I just had this and as has happened to me in the past it didn't work because I didn't pay attention to the autocomplete when trying to add the method and I actually end up implementing tableView:didDeselectRowAtIndexPath: instead of tableView:didSelectRowAtIndexPath:.

7
votes

Make sure you implemented tableView:didSelectRowAtIndexPath and not tableView:didDeSelectRowAtIndexPath

This is gotten me on more than a few occasions !!

5
votes

If your table view is in editing mode (eg. [tableView setEditing:YES animated:NO];), you need to set tableView.allowsSelectionDuringEditing = YES;

5
votes

In my case the solution was to change NO to YES in the below function.

iOS 9+

- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}
5
votes

Check if your viewController has following method:

- (BOOL) tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
    return NO;
}

if you return "NO" didSelectRow won't be called

5
votes

Please check for UITapGestureRecognizer. In my case tapgesture was added for the view where tableview got placed, which is eating the user interaction of UITableview like didselect. After disabling tapgesture for the view, didselect delegate was triggered.

4
votes

I know is old and the problem was resolved, but a had similar problem, I thought that the problem was with my custom UITableViewCell, but the solution was completely different - I restart XCode :) and then works ok ! almost like Windows :)

4
votes

Another mistake you could've done (as I did): if you set a segue at the cell, didSelectRowAtIndexPath is not called. You should set your segues at the view controller instead.

4
votes

None of these answers worked for me. After about an hour, I figured out something very insidious:

I have a table view inside a cell of another table view. I decided to make an enclosing view that contains the inner table view, among other things. I called this view contentView and hooked it up in the xib.

Turns out that UITableViewCell already has a contentView and does weird things with it. The issue resolved itself when I renamed the property to mainContentView and reconnected the view to this renamed property.