How to detect tap on clear part of UITableView?

Thanks to @Stonz2, swift version:

Swift 4

let tap = UITapGestureRecognizer(target: self, action: #selector(tableTapped))
self.tableView.addGestureRecognizer(tap)

@objc func tableTapped(tap:UITapGestureRecognizer) {
    let location = tap.location(in: self.tableView)
    let path = self.tableView.indexPathForRow(at: location)
    if let indexPathForRow = path {
        self.tableView(self.tableView, didSelectRowAt: indexPathForRow)
    } else {
        // handle tap on empty space below existing rows however you want
    }
}

Swift 3

let tap = UITapGestureRecognizer(target: self, action: #selector(tableTapped))
self.tableView.addGestureRecognizer(tap)

func tableTapped(tap:UITapGestureRecognizer) {
    let location = tap.location(in: self.tableView)
    let path = self.tableView.indexPathForRow(at: location)
    if let indexPathForRow = path {
        self.tableView(self.tableView, didSelectRowAt: indexPathForRow)
    } else {
        // handle tap on empty space below existing rows however you want
    }
}

Swift 2:

let tap = UITapGestureRecognizer(target: self, action: #selector(tableTapped))
self.tableView.addGestureRecognizer(tap)


func tableTapped(tap:UITapGestureRecognizer) {
    let location = tap.locationInView(self.tableView)
    let path = self.tableView.indexPathForRowAtPoint(location)
    if let indexPathForRow = path {
        self.tableView(self.tableView, didSelectRowAtIndexPath: indexPathForRow)
    } else {
        // handle tap on empty space below existing rows however you want
    }
}

All of the supplied answers, including the accepted answer, add a UITapGestureRecognizer to the tableView; while this will work, I've found that this gesture recognizer can interfere with row taps and triggering didSelectRowAtIndexPath in a somewhat unpredictable/nondeterministic way.

If you want to detect taps in the "blank space" as well as in rows, I highly suggest adding a background view to your table, and add the gesture recognizer there:

let tap = UITapGestureRecognizer(target: self, action: #selector(tableTapped))
self.tableView.backgroundView = UIView()
self.tableView.backgroundView?.addGestureRecognizer(tap)

Yes, there are delegate methods, such as:

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

However, this will only tell you if a tap occurs on an existing row. If you want to capture taps on the empty space below the rows (or on a section header) you will need to use a gesture recognizer. You can do something like this:

// in viewDidLoad or somewhere similar
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tableTapped:)];
[self.tableView addGestureRecognizer:tap];
//.........

- (void)tableTapped:(UITapGestureRecognizer *)tap
{
    CGPoint location = [tap locationInView:self.tableView];
    NSIndexPath *path = [self.tableView indexPathForRowAtPoint:location];

    if(path)
    {
        // tap was on existing row, so pass it to the delegate method
        [self tableView:self.tableView didSelectRowAtIndexPath:path];
    }
    else
    {
        // handle tap on empty space below existing rows however you want
    }
}

EDIT: for an alternative approach, consider Connor Neville's approach from his answer on this post and add the gesture recognizer to the table's background.