How to get UITableView from UITableViewCell?

I have a UITableViewCell which is linked to an object and I need to tell if the cell is visible. From the research I've done, this means I need to somehow access the UITableView that contains it (from there, there are several ways to check if it's visible). So I'm wondering if UITableViewCell has a pointer to the UITableView, or if there was any other way to get a pointer from the cell?


To avoid checking the iOS version, iteratively walk up the superviews from the cell's view until a UITableView is found:

Objective-C

id view = [cellInstance superview];

while (view && [view isKindOfClass:[UITableView class]] == NO) {
    view = [view superview]; 
}

UITableView *tableView = (UITableView *)view;

Swift

var view = cellInstance.superview
while (view != nil && (view as? UITableView) == nil) {
  view = view?.superview
}
        
if let tableView = view as? UITableView {
   tableView.beginUpdates()
   tableView.endUpdates()
}

In iOS7 beta 5 UITableViewWrapperView is the superview of a UITableViewCell. Also UITableView is superview of a UITableViewWrapperView.

So for iOS 7 the solution is

UITableView *tableView = (UITableView *)cell.superview.superview;

So for iOSes up to iOS 6 the solution is

UITableView *tableView = (UITableView *)cell.superview;


Swift 5 extension

Recursively

extension UIView {
    func parentView<T: UIView>(of type: T.Type) -> T? {
        guard let view = superview else {
            return nil
        } 
        return (view as? T) ?? view.parentView(of: T.self)
    }
}

extension UITableViewCell {
    var tableView: UITableView? {
        return parentView(of: UITableView.self)
    }
}

Using loop

extension UITableViewCell {
    var tableView: UITableView? {
        var view = superview
        while let v = view, v.isKind(of: UITableView.self) == false {
            view = v.superview
        }
        return view as? UITableView
    }
}

Before iOS7, the cell's superview was the UITableView that contained it. As of iOS7 GM (so presumably will be in the public release as well) the cell's superview is a UITableViewWrapperView with its superview being the UITableView. There are two solutions to the problem.

Solution #1: Create a UITableViewCell category

@implementation UITableViewCell (RelatedTable)

- (UITableView *)relatedTable
{
    if ([self.superview isKindOfClass:[UITableView class]])
        return (UITableView *)self.superview;
    else if ([self.superview.superview isKindOfClass:[UITableView class]])
        return (UITableView *)self.superview.superview;
    else
    {
        NSAssert(NO, @"UITableView shall always be found.");
        return nil;
    }

}
@end

This is a good drop-in replacement to using cell.superview, makes it easy to refactor your existing code -- just search and replace with [cell relatedTable], and throw in an assert to ensure that if the view hierarchy changes or reverts in the future it will show up immediately in your tests.

Solution #2: Add a Weak UITableView reference to UITableViewCell

@interface SOUITableViewCell

   @property (weak, nonatomic) UITableView *tableView;

@end

This is a much better design, though it will require a bit more code refactoring to use in existing projects. In your tableView:cellForRowAtIndexPath use SOUITableViewCell as your cell class or make sure your custom cell class is subclassed from SOUITableViewCell and assign the tableView to the cell's tableView property. Inside the cell you can then refer to the containing tableview using self.tableView.


If it is visible then it has a superview. And ... surprise ... the superview is an UITableView object.

However, having a superview is no guarantee for being on screen. But UITableView provides methods to determine which cells are visible.

And no, there is no dedicated reference from a cell to a table. But when you subclass UITableViewCell you may introduce one and set it upon creation. (I did that myself a lot before I thought of the subview hierarchy.)

Update for iOS7: Apple has changed the subview hierarchy here. As usual when working with things that are not detailled documented, there is always a risk that things change. It is far saver to "crawl up" the view hierarchy until a UITableView object is eventually found.