wake-up-neo.com

Wie bekomme ich UITableView von UITableViewCell?

Ich habe eine UITableViewCell, die mit einem Objekt verknüpft ist, und ich muss feststellen, ob die Zelle sichtbar ist. Nach den Recherchen, die ich durchgeführt habe, muss ich auf die UITableView zugreifen, die sie enthält (von dort gibt es mehrere Möglichkeiten, um zu überprüfen, ob sie sichtbar ist). Ich frage mich also, ob UITableViewCell einen Zeiger auf die UITableView hat oder ob es einen anderen Weg gab, einen Zeiger aus der Zelle zu bekommen?

92
sinθ

So vermeiden Sie iOS-Versionsprüfungen

id view = [tableViewCellInstance superview];

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

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

In iOS7 Beta 5 ist UITableViewWrapperView der Überblick über eine UITableViewCell. Auch UITableView ist eine Übersicht über eine UITableViewWrapperView.

Also für iOS 7 ist die Lösung

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

Also für iOS bis iOS 6 ist die Lösung

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

48
KGS-12

Swift 3 Erweiterung

Rekursiv

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)
    }
}

Schleife verwenden

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

Vor iOS7 war der Überblick der Zelle die UITableView, die sie enthielt. Ab iOS7 GM (so wird es vermutlich auch in der öffentlichen Veröffentlichung sein) ist der Superview der Zelle eine UITableViewWrapperView, wobei der Superview die UITableView ist. Es gibt zwei Lösungen für das Problem.

Lösung 1: Erstellen Sie eine UITableViewCell-Kategorie

@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

Dies ist ein guter Ersatz für die Verwendung von cell.superview. Erleichtert die Umgestaltung Ihres vorhandenen Codes. Suchen und ersetzen Sie ihn mit [cell relatedTable], und geben Sie eine Bestätigung ein, um sicherzustellen, dass sich die Ansichtshierarchie ändert oder in Zukunft rückgängig macht sofort in Ihren Tests. 

Lösung 2: Fügen Sie eine schwache UITableView-Referenz zu UITableViewCell hinzu.

@interface SOUITableViewCell

   @property (weak, nonatomic) UITableView *tableView;

@end

Dies ist ein viel besseres Design, obwohl für die Verwendung in vorhandenen Projekten etwas mehr Code-Refactoring erforderlich ist. Verwenden Sie in Ihrem tableView:cellForRowAtIndexPath SOUITableViewCell als Zellklasse oder stellen Sie sicher, dass Ihre benutzerdefinierte Zellklasse von SOUITableViewCell subclassed ist, und weisen Sie tableView der tableView-Eigenschaft der Zelle zu. Innerhalb der Zelle können Sie dann mit self.tableView auf die enthaltende Tabellenansicht verweisen. 

23
memmons

Was auch immer Sie durch das Aufrufen von Super View oder über die Responder-Kette erledigen können, wird sehr zerbrechlich sein .. Der beste Weg, dies zu tun, wenn die Zellen etwas wissen wollen, ist, ein Objekt an die Zelle zu übergeben Dies antwortet auf eine Methode, die die Frage beantwortet, die die Zelle stellen möchte, und der Controller muss die Logik implementieren, die bestimmt, was zu beantworten ist (aus Ihrer Frage schätze ich, die Zelle möchte wissen, ob etwas sichtbar ist oder nicht).

Erstellen Sie ein Delegatenprotokoll in der Zelle, setzen Sie den Delegaten der Zelle tableViewController und verschieben Sie die gesamte "Steuerungs" -Logik der UI im tableViewCotroller. 

Die Zellen der Tabellensicht sollten eine Dum-Ansicht sein, in der nur Informationen angezeigt werden. 

7
Javier Soto

Schnelle 2.2 Lösung. 

Eine Erweiterung für UIView, die rekursiv nach einer Ansicht mit einem bestimmten Typ sucht. 

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
    }
}

oder kompakter (dank kabiroberai):

import UIKit

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

In Ihrer Zelle nennen Sie es einfach:

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

Beachten Sie, dass UITableViewCell nur nach der Ausführung von cellForRowAtIndexPath in UITableView hinzugefügt wird. 

7
Mehdzor

Wenn es sichtbar ist, hat es einen Überblick. Und ... Überraschung ... der Überblick ist ein UITableView-Objekt. 

Ein Überblick zu haben ist jedoch keine Garantie für die Anzeige auf dem Bildschirm. UITableView bietet jedoch Methoden, um festzustellen, welche Zellen sichtbar sind. 

Und nein, es gibt keine dedizierte Referenz von einer Zelle zu einer Tabelle. Wenn Sie jedoch die UITableViewCell-Unterklasse definieren, können Sie eine einfügen und bei der Erstellung festlegen. (Ich habe das selbst oft gemacht, bevor ich an die Subview-Hierarchie dachte.) 

Update für iOS7: Apple hat hier die Unteransichtshierarchie geändert. Beim Arbeiten mit Dingen, die nicht detailliert dokumentiert sind, besteht immer die Gefahr, dass sich Dinge ändern. Es ist weitaus sicherer, die Ansichtshierarchie "nach oben zu durchsuchen", bis schließlich ein UITableView-Objekt gefunden wird. 

7
Hermann Klecker

Ich habe eine Kategorie in UITableViewCell erstellt, um die übergeordnete tableView abzurufen:

@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

Beste,

6
boliva

Hier ist die Swift Version basierend auf den obigen Antworten. Ich habe mich zur späteren Verwendung in ExtendedCell verallgemeinert.

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
    }
}

Ich hoffe das hilft :)

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

Ich habe etwas von der obigen Antwort geborgt und modifiziert und mir das folgende Snippet ausgedacht. 

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

Die Weitergabe in der Klasse bietet die Flexibilität, andere Ansichten als UITableView zu verwenden und andere Ansichten zu erhalten. 

2
Azu

Diese Lösung basierte auf Gabes Vorschlag, dass UITableViewWrapperView object der Überblick über UITableViewCell in iOS7 beta5 ist.

Unterklasse 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

Meine Lösung für dieses Problem ähnelt anderen Lösungen, verwendet jedoch eine elegante for-Schleife und ist kurz. Es sollte auch zukunftssicher sein:

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

Versuchen Sie anstelle von Superview, ["UItableViewvariable" visibleCells] zu verwenden.

Ich habe das in einer foreach-Schleife verwendet, um die Zellen zu durchlaufen, die die App gesehen hat, und es hat funktioniert. 

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 
    }
  }
}

Klappt wunderbar.

1
user2497493

Minimal getestet, aber dieses nicht generische Swift 3-Beispiel scheint zu funktionieren:

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

Sie können es mit einer Codezeile erhalten.

UITableView *tableView = (UITableView *)[[cell superview] superview];
0
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 Vielen Dank

0
jbchitaliya

Ich schlage vor, Sie durchlaufen die Ansichtshierarchie auf diese Weise, um das übergeordnete UITableView zu finden:

- (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 );
}

Andernfalls wird Ihr Code beschädigt, wenn Apple die Ansichtshierarchie erneut ändert

Eine andere Antwort die auch die Hierarchie durchläuft, ist rekursiv. 

0
Bob Wakefield

dieser Code `UITableView *tblView=[cell superview]; gibt Ihnen eine Instanz der UItableview, die die angezeigte Ansichtszelle enthält 

0
Singh

antwort von @idris Ich habe eine Erweiterung für UITableViewCell in Swift geschrieben

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
}