web-dev-qa-db-fra.com

Comment obtenir UITableView depuis UITableViewCell?

J'ai une UITableViewCell qui est liée à un objet et je dois dire si la cellule est visible. D'après les recherches que j'ai effectuées, cela signifie que je dois accéder d'une manière ou d'une autre à la UITableView qui la contient (à partir de là, il existe plusieurs façons de vérifier si elle est visible). Je me demande donc si UITableViewCell a un pointeur sur UITableView ou s’il existe un autre moyen d’obtenir un pointeur de la cellule?

92
sinθ

Pour éviter les vérifications de version iOS

id view = [tableViewCellInstance superview];

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

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

Dans iOS7 bêta 5 UITableViewWrapperView est la vue d'ensemble d'une UITableViewCell.UITableView est également superview d'un UITableViewWrapperView.

Donc, pour iOS 7, la solution est

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

Donc, pour iOS jusqu'à iOS 6, la solution est

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

48
KGS-12

Swift 3 extension

Récursivement

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

En utilisant la boucle

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

Avant iOS7, la superview de la cellule était la UITableView qui la contenait. À partir de iOS7 GM (il est donc probable que la version publique le sera également), la superview de la cellule est une UITableViewWrapperView, sa superview étant la UITableView. Il y a deux solutions au problème.

Solution n ° 1: Créer une catégorie 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

C’est une bonne solution de remplacement immédiate à l’utilisation de cell.superview, facilite la refactorisation de votre code existant - il suffit de chercher et de remplacer par [cell relatedTable] et de lancer une assertion pour garantir que si la hiérarchie de la vue change ou revient à l’avenir, up immédiatement dans vos tests. 

Solution n ° 2: Ajoutez une référence UITableView faible à UITableViewCell

@interface SOUITableViewCell

   @property (weak, nonatomic) UITableView *tableView;

@end

Cette conception est bien meilleure, mais elle nécessitera un peu plus de refactoring de code à utiliser dans les projets existants. Dans votre tableView:cellForRowAtIndexPath, utilisez SOUITableViewCell comme classe de cellule ou assurez-vous que votre classe de cellule personnalisée est sous-classée à partir de SOUITableViewCell et affectez la tableView à la propriété tableView de la cellule. Dans la cellule, vous pouvez ensuite vous référer à la table contenant en utilisant self.tableView

23
memmons

Quoi que vous réussissiez à faire en appelant super view ou via la chaîne de répondeurs, cela sera très fragile ... La meilleure façon de le faire, si les cellules veulent savoir quelque chose, est de passer un objet à la cellule cela répond à une méthode qui répond à la question que la cellule veut poser et demande au contrôleur de mettre en œuvre la logique de détermination de la réponse (d'après votre question, la cellule veut savoir si quelque chose est visible ou non).

Créez un protocole de délégué dans la cellule, définissez le délégué de la cellule sur tableViewController et déplacez toute la logique de "contrôle" de l'interface utilisateur dans tableViewCotroller. 

Les cellules de la vue tableau doivent être une vue dum qui n’affiche que des informations. 

7
Javier Soto

Solution Swift 2.2. 

Une extension pour UIView qui recherche de manière récursive une vue avec un type spécifique. 

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

ou plus compact (grâce à kabiroberai):

import UIKit

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

Dans votre cellulaire, vous appelez simplement cela:

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

Notez que UITableViewCell est ajouté sur UITableView uniquement après l'exécution de cellForRowAtIndexPath. 

7
Mehdzor

Si c'est visible alors il y a un superview. Et ... surprise ... la superview est un objet UITableView. 

Cependant, avoir un aperçu n'est pas une garantie d'être à l'écran. Mais UITableView fournit des méthodes pour déterminer quelles cellules sont visibles. 

Et non, il n'y a pas de référence dédiée d'une cellule à une table. Mais lorsque vous sous-classez UITableViewCell, vous pouvez en introduire un et le définir lors de la création. (Je l'ai souvent fait moi-même avant de penser à la hiérarchie des sous-vues.) 

Mise à jour pour iOS7: Apple a modifié la hiérarchie des sous-vues ici. Comme d'habitude lorsque vous travaillez avec des choses qui ne sont pas détaillées et documentées, il y a toujours un risque que les choses changent. Il est beaucoup plus économe de "parcourir" la hiérarchie des vues jusqu'à ce qu'un objet UITableView soit finalement trouvé. 

7
Hermann Klecker

J'ai créé une catégorie sur UITableViewCell pour obtenir sa tableView parent:

@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

Meilleur,

6
boliva

Voici la version Swift basée sur les réponses ci-dessus. J'ai généralisé en ExtendedCell pour une utilisation ultérieure.

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

J'espère que cette aide :)

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

J'ai emprunté et modifié un peu la réponse ci-dessus pour arriver à l'extrait suivant. 

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

Passer en classe offre la possibilité de parcourir et d’obtenir des vues autres que UITableView à d’autres occasions. 

2
Azu

J'ai fondé cette solution sur la suggestion de Gabe selon laquelle l'objet UITableViewWrapperView est la superview de l'objet UITableViewCell dans iOS7 beta5.

Sous-classe 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

Ma solution à ce problème est quelque peu similaire aux autres solutions, mais utilise une boucle for élégante et est courte. Il devrait également être à l'épreuve du temps:

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

Au lieu de superview, essayez d’utiliser ["UItableViewvariable" visibleCells].

J'ai utilisé cela dans une boucle foreach pour parcourir les cellules que l'application a vues et cela a fonctionné. 

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

Fonctionne comme un charme.

1
user2497493

Testé au minimum, mais cet exemple non générique de Swift 3 semble fonctionner:

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

Vous pouvez l'obtenir avec une ligne de code.

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 Merci

0
jbchitaliya

Je vous suggère de parcourir la hiérarchie des vues de cette manière pour trouver le UITableView parent:

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

Sinon, votre code se cassera lorsque Apple changera la hiérarchie des vues encore

Une autre réponse qui traverse également la hiérarchie est récursive. 

0
Bob Wakefield

ce code `UITableView *tblView=[cell superview]; vous donnera une instance de UItableview qui contient la cellule de vue tab 

0
Singh

de @idris answer J'ai écrit une extension pour UITableViewCell dans 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