How to get UITableViewCell indexPath from the Cell?

IphoneIosObjective CXcodeCocoa

Iphone Problem Overview


How do I, from a cell, get its indexPath in a UITableView?

I've searched around stack overflow and google, but all the information is on the other way around. Is there some way to access the superView/UITableView and then search for the cell?

More information about the context: there are two classes that I have, one is called Cue and one is called CueTableCell (which is a subclass of UITableViewCell) CueTableCell is the visual representation of Cue (both classes have pointers to each other). Cue objects are in a linked list and when the user performs a certain command, the visual representation (the CueTableCell) of the next Cue needs to be selected. So the Cue class calls the select method on the next Cue in the list, which retrieves the UITableView from the cell and calls its selectRowAtIndexPath:animated:scrollPosition:, for which it needs the indexPath of the UITableViewCell.

Iphone Solutions


Solution 1 - Iphone

NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];

It helps reading the UITableView documentation, even if this is by some regarded to be controversial (see comments below).

The cell has no business knowing what its index path is. The controller should contain any code that manipulates UI elements based on the data model or that modifies data based on UI interactions. (See MVC.)

Solution 2 - Iphone

Try with this from your UITableViewCell:

NSIndexPath *indexPath = [(UITableView *)self.superview indexPathForCell: self];

EDIT: Seems this doesn't work on iOS 8.1.2 and further. Thanks to Chris Prince for pointing it.

Solution 3 - Iphone

  1. Put a weak tableView property in cell's .h file like:

    @property (weak,nonatomic)UITableView *tableView;

  2. Assign the property in cellForRowAtIndex method like:

cell.tableView = tableView;

  1. Now wherever you need the indexPath of cell:

    NSIndexPath *indexPath = [cell.tableView indexPathForCell:cell];

Solution 4 - Iphone

You can try this simple tip:

on your UITableViewCell Class :

@property NSInteger myCellIndex; //or add directly your indexPath 

and on your cellForRowAtIndexPath method :

...
[cell setMyCellIndex : indexPath.row]

now, you can retrieve your cell index anywhere

Solution 5 - Iphone

To address those who say "this is a bad idea", in my case, my need for this is that I have a button on my UITableViewCell that, when pressed, is a segue to another view. Since this is not a selection on the cell itself, [self.tableView indexPathForSelectedRow] does not work.

This leaves me two options:

  1. Store the object that I need to pass into the view in the table cell itself. While this would work, it would defeat the point of me having an NSFetchedResultsController because I do not want to store all the objects in memory, especially if the table is long.
  2. Retrieve the item from the fetch controller using the index path. Yes, it seems ugly that I have to go figure out the NSIndexPath by a hack, but it's ultimately less expensive than storing objects in memory.

indexPathForCell: is the correct method to use, but here's how I would do it (this code is assumed to be implemented in a subclass of UITableViewCell:

// uses the indexPathForCell to return the indexPath for itself
- (NSIndexPath *)getIndexPath {
    return [[self getTableView] indexPathForCell:self];
}

// retrieve the table view from self   
- (UITableView *)getTableView {
    // get the superview of this class, note the camel-case V to differentiate
    // from the class' superview property.
    UIView *superView = self.superview;

    /*
      check to see that *superView != nil* (if it is then we've walked up the
      entire chain of views without finding a UITableView object) and whether
      the superView is a UITableView.
    */
    while (superView && ![superView isKindOfClass:[UITableView class]]) {
        superView = superView.superview;
    }
    
    // if superView != nil, then it means we found the UITableView that contains
    // the cell.
    if (superView) {
        // cast the object and return
        return (UITableView *)superView;
    }

    // we did not find any UITableView
    return nil;
}

P.S. My real code does access all this from the table view, but I'm giving an example of why someone might want to do something like this in the table cell directly.

Solution 6 - Iphone

For swift

let indexPath :NSIndexPath? = (self.superview.superview as! UITableView)?.indexPathForCell(self)

Solution 7 - Iphone

The answer to this question actually helped me a lot.

I used NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];

The sender in my case was a UITableViewCell and comes from the prepareForSegue method.

I used this because I did not have a TableViewControllerbut i had UITableView property outlet

I needed to find out the title of the Cell and hence needed to know the indexPath of it.

Hope this helps anyone!

Solution 8 - Iphone

On iOS 11.0, you can use UITableView.indexPathForRow(at point: CGPoint) -> IndexPath?:

if let indexPath = tableView.indexPathForRow(at: cell.center) {
    tableView.selectRow
    (at: indexPath, animated: true, scrollPosition: .middle)
}

It gets the center point of the cell and then the tableView returns the indexPath corresponding to that point.

Solution 9 - Iphone

try this (it only works if the tableView has only one section and all cells has equal heights) :

//get current cell rectangle relative to its superview
CGRect r = [self convertRect:self.frame toView:self.superview];

//get cell index
int index = r.origin.y / r.size.height;

Solution 10 - Iphone

Swift 3.0 and above-

If one needs to get the indexpath from within a custom cell-

if let tableView = self.superview as? UITableView{
    if let indexPath = tableView.indexPath(for: self){
        print("Indexpath acquired.")
    }else{
        print("Indexpath could not be acquired from tableview.")
    }
}else{
    print("Superview couldn't be cast as tableview")
}

It's good practice is to look out for the failure cases.

Solution 11 - Iphone

Try with this from your UITableViewCell:

NSIndexPath *indexPath = [(UITableView *)self.superview.superview indexPathForCell:self];

Solution 12 - Iphone

>Swift 4.x

To provide access to my cell, i did something like this:

I have an extension of the UIView:

extension UIView {
    var parentViewController: UIViewController? {
        var parentResponder: UIResponder? = self
        while parentResponder != nil {
            parentResponder = parentResponder!.next
            if let viewController = parentResponder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}

And then.. in my cell Class:

class SomeCell: UITableViewCell {

    func someMethod() {
        if let myViewController = self.parentViewController as? CarteleraTableViewController {
            let indexPath : IndexPath = (myViewController.tableView).indexPath(for: self)!
            print(indexPath)
        }
    }
}

Thats all form me.

Best regards.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsinθView Question on Stackoverflow
Solution 1 - IphoneMundiView Answer on Stackoverflow
Solution 2 - IphonePepperView Answer on Stackoverflow
Solution 3 - IphoneChanchal RajView Answer on Stackoverflow
Solution 4 - IphoneAITAALI_ABDERRAHMANEView Answer on Stackoverflow
Solution 5 - IphonemikehoView Answer on Stackoverflow
Solution 6 - IphoneGevorg GhukasyanView Answer on Stackoverflow
Solution 7 - IphoneCescyView Answer on Stackoverflow
Solution 8 - Iphonebanan3'14View Answer on Stackoverflow
Solution 9 - Iphonem.eldehairyView Answer on Stackoverflow
Solution 10 - IphoneNatashaView Answer on Stackoverflow
Solution 11 - IphoneYogesh KumarView Answer on Stackoverflow
Solution 12 - IphoneAndres PaladinesView Answer on Stackoverflow