60

I have a UITableView as a subview of my UIScrollVIew, which is the main view controlled by my MainViewController.

In MainViewController.h

@interface MainViewController : UIViewController <UIGestureRecognizerDelegate, UITableViewDelegate, UITableViewDataSource>

// other stuff here...

@property (weak, nonatomic) IBOutlet UITableView *myTableView;

In MainViewController.m

@synthesize myTableView;

// other stuff here...

- (void)viewDidLoad {
    myTableView.delegate = self;
    myTableView.datasource = self;
}

// other stuff here...

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath {
   [self performSegueWithIdentifier:@"listAttributesSegue" sender:self];
}

I know that didSelectRowAtIndexPath is not being called because I have set breakpoints on both the method itself and the line of code inside it, and neither is being called. I also know that the datasource is working correctly because I have other functions which modify the cells at runtime and they are working perfectly fine. I am using the latest Xcode with iOS 5.0 set as the development target. I have searched and searched for an answer. Anyone have any ideas?

Edit: I have found the answer. I had a UITapGestureRecognizer set for myTableView's superView. This overrode the selection call. Credit to whoever suggested that that might be it. Your answer was deleted before I could mark it correct.

Edit 2: A lot of people have been commenting about this, so I though I would share it. If you are experiencing this problem, simply set myGestureRecognizer.cancelsTouchInView to false and everything should work fine.

Garrett
  • 5,580
  • 2
  • 31
  • 47

14 Answers14

311

I have found the answer. I had a UITapGestureRecognizer set for myTableView's superView. This overrode the selection call. Credit to whoever suggested that that might be it. Your answer was deleted before I could mark it correct.

Set the cancelsTouchesInView property to NO on the gesture recogniser to allow the table view to intercept the event.

Adam Waite
  • 19,175
  • 22
  • 126
  • 148
Garrett
  • 5,580
  • 2
  • 31
  • 47
  • 15
    This was the problem for me, my coworker added a UITapGestureRecognizer to a close-to-root-level view that was eating my tap events. The misleading thing was, however, that the table cells would still highlight when they were tapped, so I didn't suspect anything was intercepting those events. – bugloaf Nov 02 '12 at 16:14
  • 15
    This is the problem for me as well. Make sure to check cancelsTouchesInView property of gesture recognizer. If it is YES, then it eats the event. – Echo Lu Jan 28 '13 at 00:49
  • Thank you a lot, really saved my day. Didn't realize that a UITapGestureRecognizer added from the storyboard would prevent the function from being called! Curiously the UITableViewCells where still highlighting on Taps. – David Feb 13 '13 at 15:19
  • 1
    I had `touchesBegan` and `touchesEnded` overridden in the cell class and I forgot about it. Thanks for saving me lots of time. – chitza Apr 10 '13 at 20:32
  • 9
    I ran into the same problem today. I had a UITapGestureRecognizer added in code (to dismiss the keyboard when the user taps outside the search field), and this was swallowing the taps. Here's how to recognize this situation: your rows highlight, but didSelectRowAtIndexPath only fires if you tap, hold, slide your finger a bit left or right, and then release (because that is NOT recognized as a tap). The simple fix: tap.cancelsTouchesInView = NO; – Joe Strout Oct 22 '13 at 22:38
  • Even I faced same problem, I was showing tableview when a label is tapped(was identifying tap using tap gesture). Wasted some 3hr to figure out why... – Chandan Shetty SP Jul 05 '14 at 04:15
  • It turns out that a Gesture Recognizer was part of the problem, but I was not able to override it because it resided in a 3rd party lib (within a Pod). Thus my solution was to simply put a `UITapGestureRecognizer` on the custom sublass of `UITableViewCell`. – ded Aug 08 '15 at 23:56
16

Updated for Swift 3:

if you are used UITapGestureRecognizer in your code :- # Swift 3 use below lines of code:

extension YourViewController{
    func hideKeyboardWhenTappedAround() {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(YourViewController.dismissKeyboard))
        view.addGestureRecognizer(tap)
        tap.cancelsTouchesInView = false
    }

    func dismissKeyboard() {
        view.endEditing(true)
    }
}

How to called:- In ViewDidLoad()

self.hideKeyboardWhenTappedAround()
Kiran Jadhav
  • 3,209
  • 26
  • 29
10

Your problem is case-sensitivity. Your code:

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

should be

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath {
luk2302
  • 55,258
  • 23
  • 97
  • 137
A. Wilcox
  • 1,782
  • 2
  • 12
  • 18
  • 1
    that was a good catch, but the mistake was merely a typo while copying my code into the question, it is right in my app – Garrett Jan 21 '12 at 13:17
  • 1
    The "i" in the first "tableView" is capitalised in the first (errant) version. – A. Wilcox Mar 18 '15 at 18:47
7

My solution is :

  1. set cancelsTouchesInView To No of any tapGesture

  2. I found in my custom cell , userInteractionEnable is set to NO, simply delete userInteractionEnable = No and issue solved.

PeiweiChen
  • 413
  • 5
  • 16
7

Have you defined instance variable for tableview with same name. If not then might be this can be the issue-

_myTableView.delegate = self;
_myTableView.datasource = self;

Or-

self.myTableView.delegate = self;
self.myTableView.datasource = self;
rishi
  • 11,779
  • 4
  • 40
  • 59
  • 2
    Awesome! Search long and wide for this problem, and the issue was that I had not set: self.tableView.delegate = self; – hbruce Jan 24 '12 at 21:01
7

Maybe it is a typo after all. Check that your function is not didDeselectRowAtIndexPath: (de select instead of select).

Mundi
  • 79,884
  • 17
  • 117
  • 140
3

Cancel the other views touches except required one.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gesture shouldReceiveTouch:(UITouch *)touch {
    if (touch.view == your view) {
        return YES;
    }
    return NO;
}
MuraliMohan
  • 1,063
  • 1
  • 11
  • 30
1

Sorry, haven't got enough points to add comments - Garret's answer is great but I would add:

You can still have your gesture recognizer but you will need to set 'Cancels touches in view' to NO - then the gestures will be handed on to the view and your UITableView will work fine.

After trying many, many approaches this seems to be the correct way of doing things: a tap gesture recognizer with 'cancel touches in view' is like having an invisible layer on top of everything that grabs all the events and routes them to the view controller (the proxy). The view controller then looks at the gesture to see if it has an action binding (buttons etc.) and will route those and any remaining will just go to the gesture handler. When using a UITableView it is expecting to receive the tap but the view controller snaffles it when you have 'Cancels touches in view'.

Oly Dungey
  • 1,603
  • 19
  • 20
1

I was having this issue for a while, and I did not see any reference to it here, so for reference, another reason for this could be that:

tableView.editing = YES;

but

tableView.allowsSelectionDuringEditing = NO;

As per documentation for

- tableView:didSelectRowAtIndexPath:

This method isn’t called when the editing property of the table is set to YES (that is, the table view is in editing mode). See "Managing Selections" in Table View Programming Guide for iOS for further information (and code examples) related to this method.

Bamaco
  • 592
  • 9
  • 25
1

My case is strange. My tableView has 2 sections. 1st section's cells work fine about tableView:didSelectRowAt:, but 2nd section's cells doesn't trigger didSelectRowAt:.

The above problem happens at iPhone 4s, iOS 9.3. But in iPhone 5s, iOS 10.3, there are no problems, those cells works fine. It seems like iOS 9 bugs about UITableView.

After many tests, I found out one line codes produces this bug.

tableView.estimatedSectionHeaderHeight = 60.0

Because the 2nd sections has no header view. I remove this line, and all works fine.

AechoLiu
  • 17,522
  • 9
  • 100
  • 118
0

A cell can be selected by the user (tapping on the row), by calling "tableView.selectRowAtIndexPath(..)" or "cell.setSelected(true, ...).

  • If the cell is selected by calling "cell.setSelected(true)", the user cannot deselect the cell anymore.

  • If the cell is selected by calling "tableView.selectRowAtIndexPath()", the user can deselect the cell as expected.

93sauu
  • 3,770
  • 3
  • 27
  • 43
0

I had intermittent failure of didSelectRowAtIndexPath: being called on my custom cell press.

I discovered that if I stopped calling [tableView reloadData] very often (10 Hz), and changed it to update every 2 seconds, almost every press would successfully call didSelectRowAtIndexPath:

It seems like reloading the view blocks presses.

aaronsti
  • 539
  • 4
  • 5
0

My problem is the cell is a customized cell, and the action does not work on it. In addition, there is a UITapGestureRecognizer defined in the superclass.

Firstly, Set tapGesture.cancelsTouchesInView = false

    override func viewDidLoad() {
        super.viewDidLoad()
        
        initUI()
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(endEditing))
        tapGesture.cancelsTouchesInView = false
        view.addGestureRecognizer(tapGesture)
    }

Secondly, Instead of setting isUserInteractionEnabled = true; in the table view, I set the action on the cell.

In the ViewDidLoad()

        super.viewDidLoad()
        
        tableView.delegate = self
    }

Then in the

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let cell: UITableView = tableView.dequeueReusableCell(for: indexPath)
        cell.isUserInteractionEnabled = true;

You can try this solution if you are creating a customized cell.

Aladdin
  • 1
  • 1
-1

It's work for me, can you try!

let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard)) tap.cancelsTouchesInView = false view.addGestureRecognizer(tap)

Trang Đỗ
  • 160
  • 1
  • 9