Référence de UITableViewCell au parent UITableView?

Existe-t-il un moyen d’accéder à la propriété UITableView partir d’un UITableViewCell ?

Stockez une référence weak à la tableView dans la cellule, que vous définissez dans -tableView:cellForRowAtIndexPath: de la source de données de votre table.

C’est mieux que de compter sur self.superview pour toujours être exactement la tableView est fragile. Qui sait comment Apple pourrait réorganiser la hiérarchie des UITableView de UITableView à l’avenir.

Voici une façon plus simple de le faire, qui ne repose sur aucune hiérarchie UITableView particulière. Il fonctionnera avec toute future version iOS, à condition que UITableView ne change pas complètement le nom de la classe. Non seulement cela est extrêmement improbable, mais si cela se produit, vous devrez tout de même retoucher votre code.

[myCell parentTableView] simplement la catégorie ci-dessous et obtenez votre référence avec [myCell parentTableView]

 @implementation UIView (FindUITableView) -(UITableView *) parentTableView { // iterate up the view hierarchy to find the table containing this cell/view UIView *aView = self.superview; while(aView != nil) { if([aView isKindOfClass:[UITableView class]]) { return (UITableView *)aView; } aView = aView.superview; } return nil; // this view is not within a tableView } @end 

 // To use it, just import the category and invoke it like so: UITableView *myTable = [myTableCell parentTableView]; // It can also be used from any subview within a cell, from example // if you have a UILabel within your cell, you can also do: UITableView *myTable = [myCellLabel parentTableView]; // NOTE: // If you invoke this on a cell that is not part of a UITableView yet // (ie, on a cell that you just created with [[MyCell alloc] init]), // then you will obviously get nil in return. You need to invoke this on cells/subviews // that are already part of a UITableView. 

METTRE À JOUR
Dans les commentaires, il est question de savoir si conserver une référence faible est une meilleure approche. Cela dépend de votre situation. La traversée de la hiérarchie de vues comporte une petite pénalité à l’exécution car vous bouclez jusqu’à ce que l’UIView cible soit identifié. Quelle est la profondeur de vos vues? D’autre part, conserver une référence sur chaque cellule a une pénalité de mémoire minimale (une référence faible est un pointeur après tout), et l’ajout de relations d’object là où elles ne sont pas nécessaires est considéré comme une mauvaise pratique de conception OO pour de nombreuses raisons. être évité (voir les détails dans les commentaires ci-dessous).

Plus important encore, conserver des références de table à l’intérieur des cellules ajoute de la complexité au code et peut entraîner des erreurs, car UITableViewCells sont réutilisables. Ce n’est pas un hasard si UIKit n’inclut pas de propriété cell.parentTable . Si vous définissez le vôtre, vous devez append du code pour le gérer, et si vous ne le faites pas de manière efficace, vous pouvez introduire des memory leaks (les cellules survivent après la durée de vie de leur table).

Parce que vous utiliserez généralement la catégorie ci-dessus lorsqu’un utilisateur interagit avec une cellule (exécutez pour une seule cellule), et non lorsque vous [tableView:cellForRowAtIndexPath:] la table dans [tableView:cellForRowAtIndexPath:] (exécutez pour toutes les cellules visibles), le runtime le coût devrait être insignifiant.

Xcode 7 beta, Swift 2.0

Cela fonctionne bien pour moi, à mon avis, cela n’a rien à voir avec la hiérarchie ou autre chose. Je n’ai eu aucun problème avec cette approche jusqu’à présent. Je l’ai utilisé pour de nombreux rappels asynchrones (ex. Quand une requête API est effectuée).

Classe TableViewCell

 class ItemCell: UITableViewCell { var updateCallback : ((updateList: Bool)-> Void)? //add this extra var @IBAction func btnDelete_Click(sender: AnyObject) { let localStorage = LocalStorage() if let description = lblItemDescription.text { //I delete it here, but could be done at other class as well. localStorage.DeleteItem(description) } updateCallback?(updateList : true) } } 

Classe de vue de table interne qui implémente le DataSource et le délégué

 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell: ItemCell = self.ItemTableView.dequeueReusableCellWithIdentifier("ItemCell") as! ItemCell! cell.updateCallback = UpdateCallback //add this extra line cell.lblItemDescription?.text = self.SomeList[indexPath.row].Description return cell } func UpdateCallback(updateTable : Bool) //add this extra method { licensePlatesList = localStorage.LoadNotificationPlates() LicenseTableView.reloadData() } 

Bien sûr, vous pouvez mettre n’importe quelle variable dans updateCallback et modifier sa fonction dans la tableView conséquence.

Quelqu’un voudra peut-être me dire s’il est préférable de l’utiliser, juste pour être sûr.

Vous devez append une référence à la UITableView lorsque vous construisez la cellule de vue de table.

Cependant, presque certainement ce que vous voulez vraiment est une référence à votre UITableViewController … qui nécessite la même chose, définissez-le comme un délégué de la cellule lorsque vous générez la cellule et la remettez à la vue table.

Une autre approche consiste à créer des cellules dans IB, avec le contrôleur de vue de table en tant que propriétaire des fichiers, puis à connecter des boutons dans la cellule aux actions du contrôleur de vue de table. Lorsque vous chargez la cellule xib avec loadNibNamed, transmettez le contrôleur de vue en tant que propriétaire et les actions du bouton seront renvoyées au contrôleur de vue de table.

Si vous avez des classes personnalisées pour vos UITableViewCells, vous pouvez append une variable de type id dans l’en-tête de votre cellule et synthétiser la variable. Une fois que vous avez défini la variable lorsque vous chargez la cellule, vous êtes libre de faire ce que vous voulez avec la tableview ou toute autre vue supérieure sans trop de tracas ni de surcharge.

cell.h

  // interface id root; // propery @property (nonatomic, retain) id root; 

cellule.m

@synthesize racine;

tableviewcontroller.m

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // blah blah, traditional cell declaration // but before return cell; cell.root = tableView; } 

Vous pouvez maintenant appeler n’importe quelle méthode de tableview depuis votre cellule en utilisant la variable racine. (par exemple, [reloadData]);

Ah, ça me ramène au bon vieux temps de la programmation flash.

Les deux méthodes dans les autres réponses sont les suivantes: (A) stocker une référence à la table ou (B) parcourir les superviews.

J’utiliserais toujours quelque chose comme (A) pour les objects de modèle et (B) pour les cellules de tableau.

Cellules

Si vous avez affaire à un UITableViewCell, alors vous devez soit avoir UITableView sous la main (par exemple, vous êtes dans une méthode de délégué de table), soit gérer une cellule visible dans la hiérarchie des vues. Sinon, il se peut que vous fassiez quelque chose de mal (notez le “peut-être bien”).

Les cellules sont largement réutilisées et si vous en avez une qui n’est pas visible, la seule raison réelle de cette cellule est due à l’optimisation des performances iOS UITableView (une version iOS plus lente aurait libéré la cellule lorsqu’elle aurait quitté l’écran) ) ou parce que vous en avez une référence spécifique. Je suppose que c’est probablement la raison pour laquelle les cellules de table ne sont pas dotées d’une méthode d’instance tableView.

Donc, (B) donne le bon résultat pour tous les iOS jusqu’à présent, et tous les futurs jusqu’à ce qu’ils changent radicalement le fonctionnement des vues.

Bien que pour éviter d’écrire du code généralisable encore et encore, j’utiliserais ceci:

 +(id)enclosingViewOfView:(UIView*)view withClass:(Class)returnKindOfClass { while (view&&![view isKindOfClass:returnKindOfClass]) view=view.superview; return(view); } 

et une méthode pratique:

 +(UITableView*)tableForCell:(UITableViewCell*)cell { return([self enclosingViewOfView:cell.superview withClass:UITableView.class]); } 

(ou catégories si vous le souhaitez)

BTW, si vous êtes préoccupé par l’effet d’une boucle avec une vingtaine d’itérations de cette taille sur les performances de votre application, ne le faites pas.

Des modèles

Si vous parlez de l’object modèle affiché dans la cellule, alors ce modèle pourrait / devrait certainement connaître son modèle parent, qui peut être utilisé pour rechercher ou déclencher des modifications dans la ou les tables que le modèle de la cellule pourrait utiliser. être affiché comme. (A), mais moins fragile avec les futures mises à jour iOS (par exemple, un jour, il pourrait faire en sorte que le cache de réutilisation UITableViewCell existe par réutilisationidentifier plutôt que par réutilisateuridentifier par tableview). la méthode de référence va se briser).

La méthode du modèle serait utilisée pour les modifications des données affichées dans la cellule (modifications du modèle), car les modifications se propagent partout où le modèle est affiché (par exemple, un autre UIViewController ailleurs dans l’application, la journalisation, etc.).

La méthode de cellule serait utilisée pour les actions de tableview, ce qui serait probablement une mauvaise idée si la cellule n’est même pas une sous-vue d’une table (bien que ce soit votre code, devenez fou).

Dans les deux cas, utilisez un test unitaire plutôt que de supposer que le code apparemment plus propre fonctionne uniquement lorsqu’il met à jour iOS.

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