it-roy-ru.com

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

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

92
sinθ

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

id view = [tableViewCellInstance superview];

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

    UITableView *tableView = (UITableView *)view;
150
idris

В iOS7 бета 5 UITableViewWrapperView является супервизором UITableViewCell. Также UITableView является супервизором UITableViewWrapperView.

Так что для iOS 7 решение

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

Таким образом, для iOS до iOS 6 решение

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

48
KGS-12

Расширение 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
    }
}
29
Orkhan Alikhanov

До 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 свойству tableView ячейки. Внутри ячейки вы можете затем обратиться к содержащему табличное представление, используя self.tableView

23
memmons

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

Создайте протокол делегата в ячейке, установите делегата ячейки tableViewController и переместите всю «управляющую» логику пользовательского интерфейса в tableViewCotroller. 

Ячейки табличного представления должны быть dum view, который будет отображать только информацию. 

7
Javier Soto

Решение 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
    }
}

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

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. 

7
Mehdzor

Если это видно, то у него есть суперпредставление. И ... удивительно ... суперпредставление является объектом UITableView. 

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

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

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

7
Hermann Klecker

Я создал категорию на 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

Лучший,

6
boliva

Вот версия 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
    }
}

Надеюсь это поможет :)

3
hqt
UITableView *tv = (UITableView *) self.superview.superview;
BuyListController *vc = (BuyListController *) tv.dataSource;
2
Gank

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

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

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

2
Azu

Я основал это решение на предположении Гейба, что объект 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];
}
2
Carina

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

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

Вместо superview, попробуйте использовать ["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 
    }
  }
}

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

1
user2497493

Минимально протестировано, но этот неуниверсальный пример 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
    }
}
1
Murray Sagal
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
    }
}
0
neoneye

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

UITableView *tableView = (UITableView *)[[cell superview] superview];
0
Karthik damodara
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 Спасибо

0
jbchitaliya

Я предлагаю вам пройти иерархию представлений таким образом, чтобы найти родительский 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 изменит иерархию представлений снова

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

0
Bob Wakefield

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

0
Singh

от @idris answer Я написал расширение для UITableViewCell в Swift

extension UITableViewCell {
func relatedTableView() -> UITableView? {
    var view = self.superview
    while view != nil && !(view is UITableView) {
        view = view?.superview
    }

    guard let tableView = view as? UITableView else { return nil }
    return tableView
}
0
Kiattisak Anoochitarom