Как получить UITableView из UITableViewCell?

У меня есть UITableViewCell, связанный с объектом, и мне нужно определить, видима ли ячейка. Из проведенного мной исследования это означает, что мне нужно каким-то образом получить доступ к UITableView, который содержит его (оттуда есть несколько способов проверить, видимо ли это). Поэтому мне интересно, имеет ли UITableViewCell указатель на UITableView, или если есть какой-либо другой способ получить указатель из ячейки?

Ответ 1

Чтобы избежать проверки версии iOS

id view = [tableViewCellInstance superview];

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

    UITableView *tableView = (UITableView *)view;

Ответ 2

В iOS7 beta 5 UITableViewWrapperView - это просмотр UITableViewCell. Также UITableView - это просмотр UITableViewWrapperView.

Итак, для iOS 7 решение

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

Итак, для iOSes до iOS 6 решение

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

Ответ 3

Прежде чем iOS7, супервизор ячейки был UITableView, который содержал его. Начиная с iOS7 GM (предположительно, в публичном релизе) супервизор ячейки - это UITableViewWrapperView, а его супервизор - UITableView. Существует два решения проблемы.

Решение №1: Создайте категорию UITableViewCell

@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

Это хорошая замена для замены cell.superview, упрощает реорганизацию существующего кода - просто выполните поиск и замените с помощью [cell relatedTable], а затем введите assert, чтобы убедиться, что если иерархия представления изменилась или в будущем он будет появляться сразу же в ваших тестах.

Решение №2: добавьте слабую ссылку UITableView на UITableViewCell

@interface SOUITableViewCell

   @property (weak, nonatomic) UITableView *tableView;

@end

Это гораздо лучший дизайн, хотя для существующих проектов потребуется немного больше рефакторинга кода. В вашем tableView:cellForRowAtIndexPath используйте SOUITableViewCell в качестве класса ячеек или убедитесь, что ваш собственный класс ячеек подклассифицирован из SOUITableViewCell и присваивает tableView свойству cellView таблицы. Внутри ячейки вы можете обратиться к содержащему таблицу с помощью self.tableView.

Ответ 4

Расширение Swift 3

Рекурсивный

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

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

Использование цикла

extension UITableViewCell {
    var tableView: UITableView? {
        var view = self.superview
        while (view != nil && view!.isKind(of: UITableView.self) == false) {
            view = view!.superview
        }
        return view as? UITableView
    }
}

Ответ 5

Если он виден, он имеет супервизор. И... сюрприз... супервизор - это объект UITableView.

Однако наличие супервизора не является гарантией того, что вы находитесь на экране. Но UITableView предоставляет методы для определения того, какие ячейки видны.

И нет, нет специальной ссылки из ячейки в таблицу. Но когда вы подклассифицируете UITableViewCell, вы можете ввести его и установить его при создании. (Я сделал это сам, прежде чем я подумал о иерархии subview.)

Обновление для iOS7: Apple изменила иерархию subview здесь. Как обычно, при работе с вещами, которые не описаны подробно, всегда есть риск, что все изменится. Очень удобно "обходить" иерархию представлений до тех пор, пока объект UITableView не будет найден.

Ответ 6

Я создал категорию в UITableViewCell, чтобы получить родительский tableView:

@implementation UITableViewCell (ParentTableView)


- (UITableView *)parentTableView {
    UITableView *tableView = nil;
    UIView *view = self;
    while(view != nil) {
        if([view isKindOfClass:[UITableView class]]) {
            tableView = (UITableView *)view;
            break;
        }
        view = [view superview];
    }
    return tableView;
}


@end

Бест,

Ответ 7

Все, что вы в конечном итоге можете сделать, вызывая супер-просмотр или через цепочку ответчиков, будет очень хрупким. Лучший способ сделать это, если ячейки хотят что-то знать, - передать объект в ячейку, которая отвечает на какой-либо метод, который отвечает на вопрос, который хочет задать ячейка, и чтобы контроллер реализовал логику определения того, что ответить (из вашего вопроса, я думаю, ячейка хочет знать, что-то видимо или нет).

Ответ 8

Swift 2.2.

Расширение для UIView, которое рекурсивно ищет представление определенного типа.

import UIKit

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

или более компактный (благодаря kabiroberai):

import UIKit

extension UIView {
    func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? {
        return superview as? T ?? superview?.superviewOfType(type)
    }
}

В вашей ячейке вы просто назовете это:

let tableView = self.lookForSuperviewOfType(UITableView)
// Here we go

Помните, что UITableViewCell добавляется в UITableView только после выполнения cellForRowAtIndexPath.

Ответ 9

Вот версия Swift, основанная на приведенных выше ответах. Я обобщен в ExtendedCell для последующего использования.

import Foundation
import UIKit

class ExtendedCell: UITableViewCell {

    weak var _tableView: UITableView!

    func rowIndex() -> Int {
        if _tableView == nil {
            _tableView = tableView()
        }

        return _tableView.indexPathForSelectedRow!.row
    }

    func tableView() -> UITableView! {
        if _tableView != nil {
            return _tableView
        }

        var view = self.superview
        while view != nil && !(view?.isKindOfClass(UITableView))! {
            view = view?.superview
        }

        self._tableView = view as! UITableView
        return _tableView
    }
}

Надеюсь, что эта помощь:)

Ответ 10

Я основал это решение по предложению Гейба, что объект UITableViewWrapperView - это супервизор объекта UITableViewCell в iOS7 beta5.

Подкласс UITableViewCell:

- (UITableView *)superTableView
{
    return (UITableView *)[self findTableView:self];
}

- (UIView *)findTableView:(UIView *)view
{
    if (view.superview && [view.superview isKindOfClass:[UITableView class]]) {
        return view.superview;
    }
    return [self findTableView:view.superview];
}

Ответ 11

Я заимствовал и немного изменил этот ответ и придумал следующий фрагмент.

- (id)recursivelyFindSuperViewWithClass:(Class)clazz fromView:(id)containedView {
    id containingView = [containedView superview];
    while (containingView && ![containingView isKindOfClass:[clazz class]]) {
        containingView = [containingView superview];
    }
    return containingView;
}

Прохождение в классе предлагает гибкость для перемещения и получения других точек зрения, кроме UITableView, в некоторых случаях.

Ответ 12

Мое решение этой проблемы несколько похоже на другие решения, но использует элегантный для цикла и является коротким. Он также должен быть надежным в будущем:

- (UITableView *)tableView
{
    UIView *view;
    for (view = self.superview; ![view isKindOfClass:UITableView.class]; view = view.superview);
    return (UITableView *)view;
}

Ответ 13

UITableView *tv = (UITableView *) self.superview.superview;
BuyListController *vc = (BuyListController *) tv.dataSource;

Ответ 14

Вместо супервизора попробуйте использовать [ "UItableViewvariable" visibleCells].

Я использовал это в петлях foreach для прокрутки ячеек, которые видел приложение, и это сработало.

for (UITableView *v in [orderItemTableView visibleCells])//visibleCell is the fix.
{
  @try{
    [orderItemTableView reloadData];
    if ([v isKindOfClass:[UIView class]]) {
        ReviewOrderTableViewCell *cell = (ReviewOrderTableViewCell *)v;
        if (([[cell deleteRecord] intValue] == 1) || ([[[cell editQuantityText] text] intValue] == 0))
            //code here 
    }
  }
}

Работает как шарм.

Ответ 15

Минимально проверенный, но этот не общий пример Swift 3 работает:

extension UITableViewCell {
    func tableView() -> UITableView? {
        var currentView: UIView = self
        while let superView = currentView.superview {
            if superView is UITableView {
                return (superView as! UITableView)
            }
            currentView = superView
        }
        return nil
    }
}

Ответ 16

этот код `UITableView *tblView=[cell superview]; предоставит вам экземпляр UItableview, который содержит ячейку просмотра табуляции

Ответ 17

Я предлагаю вам пройти иерархию представлений таким образом, чтобы найти родительский UITableView:

- (UITableView *) findParentTableView:(UITableViewCell *) cell
{
    UIView *view = cell;
    while ( view && ![view isKindOfClass:[UITableView class]] )
    {
#ifdef DEBUG
        NSLog( @"%@", [[view  class ] description] );
#endif
        view = [view superview];
    }

    return ( (UITableView *) view );
}

В противном случае ваш код сломается, когда Apple снова изменит иерархию представления.

Другой ответ, который также пересекает иерархию, является рекурсивным.

Ответ 18

UITableViewCell Internal View Hierarchy Change in iOS 7

Using iOS 6.1 SDK

    <UITableViewCell>
       | <UITableViewCellContentView>
       |    | <UILabel>

Using iOS 7 SDK

    <UITableViewCell>
       | <UITableViewCellScrollView>
       |    | <UIButton>
       |    |    | <UIImageView>
       |    | <UITableViewCellContentView>
       |    |    | <UILabel>


The new private UITableViewCellScrollView class is a subclass of UIScrollView and is what allows this interaction:


![enter image description here][1]


  [1]: http://i.stack.imgur.com/C2uJa.gif

http://www.curiousfind.com/blog/646 Благодарю вас.

Ответ 19

Вы можете получить его с помощью одной строки кода.

UITableView *tableView = (UITableView *)[[cell superview] superview];

Ответ 20

extension UIView {
    func parentTableView() -> UITableView? {
        var viewOrNil: UIView? = self
        while let view = viewOrNil {
            if let tableView = view as? UITableView {
                return tableView
            }
            viewOrNil = view.superview
        }
        return nil
    }
}