Gibt es eine Möglichkeit, UITableView
innerhalb von a auf das Eigentum zuzugreifen UITableViewCell
?
Gibt es eine Möglichkeit, UITableView
innerhalb von a auf das Eigentum zuzugreifen UITableViewCell
?
Antworten:
Speichern Sie einen weak
Verweis auf die tableView in der Zelle, die Sie in -tableView:cellForRowAtIndexPath:
der dataSource Ihrer Tabelle festgelegt haben.
Dies ist besser, als sich darauf self.superview
zu verlassen , dass immer genau die tableView zerbrechlich ist. Wer weiß, wie Apple UITableView
in Zukunft die Ansichtshierarchie neu organisieren könnte.
cell.superview
? In diesem Fall handelt es sich möglicherweise nicht um die Tabelle. Daher wird hier von der UITableView-Implementierung
Category
Folgenden vorgeschlagen. Dies garantiert, dass es in zukünftigen Versionen funktioniert. Auf diese Weise müssen Sie Referenzen nicht über Ihren gesamten Code verteilen und die Objektkopplung erhöhen.
Hier ist eine schönere Möglichkeit, die sich nicht auf eine bestimmte UITableView-Hierarchie stützt. Es funktioniert mit jeder zukünftigen iOS-Version, vorausgesetzt, UITableView
der Klassenname wird nicht vollständig geändert. Nicht nur das ist äußerst unwahrscheinlich, auch wenn dies passiert, müssen Sie Ihren Code trotzdem retuschieren.
Importieren Sie einfach die unten stehende Kategorie und erhalten Sie Ihre Referenz mit [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
// (i.e., 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.
UPDATE
In den Kommentaren wird diskutiert, ob es besser ist, eine schwache Referenz beizubehalten. Es hängt von Ihren Umständen ab. Das Durchlaufen der Ansichtshierarchie hat eine kleine Laufzeitstrafe, da Sie eine Schleife ausführen, bis die Ziel-UIView identifiziert ist. Wie tief sind deine Ansichten? Auf der anderen Seite hat das Behalten einer Referenz in jeder Zelle eine minimale Speicherstrafe (eine schwache Referenz ist schließlich ein Zeiger), und das Hinzufügen von Objektbeziehungen, bei denen sie nicht benötigt werden, wird aus vielen Gründen als schlechte OO-Entwurfspraxis angesehen und sollte dies auch tun vermieden werden (siehe Details in den Kommentaren unten).
Noch wichtiger ist, dass das Beibehalten von Tabellenreferenzen in Zellen die Codekomplexität erhöht und zu Fehlern führen kann, da sie UITableViewCells
wiederverwendbar sind. Es ist kein Zufall, dass UIKit
keine cell.parentTable
Eigenschaft enthalten ist. Wenn Sie Ihren eigenen definieren, müssen Sie Code hinzufügen, um ihn zu verwalten. Wenn Sie dies nicht effektiv tun, können Sie Speicherlecks einführen (dh Zellen leben über die Lebensdauer ihrer Tabelle hinaus).
Da Sie normalerweise die oben genannte Kategorie verwenden, wenn ein Benutzer mit einer Zelle interagiert (für eine einzelne Zelle ausführen) und nicht, wenn Sie die Tabelle [tableView:cellForRowAtIndexPath:]
auslegen (für alle sichtbaren Zellen ausführen), sollten die Laufzeitkosten unbedeutend sein.
UITableViewCell
ist durch das Design eingeschränkt UIKit
, unter a zu leben UITableView
. Wenn Sie auf eine Weise nach einer Instanz suchen, entstehen keine zusätzlichen Beziehungen. Das soll dann in Software Eng sein. Im Gegensatz dazu wird das Beibehalten eines Verweises auf eine bestimmte Instanz innerhalb von a als enge Kopplung angesehen, da eine direkte Beziehung eingeführt wird. Es ist kein Zufall, dass in UIKit keine Immobilie angeboten wird. UITableView
UIView hierarchy-agnostic
UITableViewCell
loosely coupled
UITableView
UITableViewCell
UITableViewCell.parentTable
Xcode 7 Beta, Swift 2.0
Das funktioniert gut für mich, meiner Meinung nach hat es nichts mit der Hierarchie oder was auch immer zu tun. Ich hatte bisher keine Probleme mit diesem Ansatz. Ich habe dies für viele asynchrone Rückrufe verwendet (z. B. wenn eine API-Anforderung ausgeführt wird).
TableViewCell-Klasse
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)
}
}
Innerhalb der Tabellenansichtsklasse, die DataSource und Delegate implementiert
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()
}
Natürlich können Sie jede Variable in die einfügen updateCallback
und ihre Funktion tableView
entsprechend ändern .
Jemand möchte mir vielleicht sagen, ob es sicher ist, es zu verwenden, nur um sicherzugehen.
cell.updateCallback2 = UpdateCallback2
?
updateCallback?(updateList : true)
. Wenn der Rückruf eingestellt ist, erfolgt der Anruf.
Sie müssen einen Verweis zurück zur UITableView hinzufügen, wenn Sie die Tabellenansichtszelle erstellen.
Mit ziemlicher Sicherheit möchten Sie jedoch einen Verweis auf Ihren UITableViewController, der dasselbe erfordert. Legen Sie ihn beim Erstellen der Zelle als Delegaten der Zelle fest und übergeben Sie ihn der Tabellenansicht.
Ein alternativer Ansatz, wenn Sie Aktionen verkabeln, besteht darin, die Zellen in IB mit dem Tabellenansichts-Controller als Dateieigentümer zu erstellen und dann die Schaltflächen in der Zelle mit den Aktionen im Tabellenansichts-Controller zu verbinden. Wenn Sie die Zelle xib mit loadNibNamed laden, übergeben Sie den Ansichts-Controller als Eigentümer, und die Schaltflächenaktionen werden mit dem Tabellenansichts-Controller verbunden.
Wenn Sie benutzerdefinierte Klassen für Ihre UITableViewCells haben, können Sie eine ID vom Typ id in den Header Ihrer Zelle einfügen und die Variable synthetisieren. Nachdem Sie die Variable beim Laden der Zelle festgelegt haben, können Sie mit der Tabellenansicht oder einer anderen höheren Ansicht ohne großen Aufwand und Aufwand tun, was Sie möchten.
cell.h
// interface
id root;
// propery
@property (nonatomic, retain) id root;
cell.m
@synthesize root;
tableviewcontroller.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// blah blah, traditional cell declaration
// but before return cell;
cell.root = tableView;
}
Jetzt können Sie mithilfe der Stammvariablen eine der Methoden der Tabellenansicht aus Ihrer Zelle heraus aufrufen. (zB [root reloadData]);
Ah, bringt mich zurück zu den guten alten Zeiten der Flash-Programmierung.
@property (nonatomic, assign) id root;
Die beiden Methoden in anderen Antworten sind: (A) Speichern eines Verweises auf die Tabelle oder (B) Aufrufen der Übersichten.
Ich würde immer so etwas wie (A) für Modellobjekte und (B) für Tabellenzellen verwenden.
Wenn Sie mit einer UITableViewCell arbeiten, müssen Sie bei AFAIK entweder die UITableView zur Hand haben (sagen wir, Sie befinden sich in einer Tabellendelegatmethode) oder mit einer sichtbaren Zelle, die sich in der Ansichtshierarchie befindet. Andernfalls machen Sie möglicherweise etwas falsch (bitte beachten Sie das "möglicherweise").
Zellen werden großzügig wiederverwendet. Wenn Sie eine Zelle haben, die nicht sichtbar ist, liegt der einzige wirkliche Grund für die Existenz der Zelle in der Leistungsoptimierung von iOS UITableView (eine langsamere iOS-Version hätte die Zelle freigegeben und hoffentlich freigegeben, wenn sie vom Bildschirm verschoben wurde ) oder weil Sie einen bestimmten Verweis darauf haben. Ich denke, dies ist wahrscheinlich der Grund, warum Tabellenzellen nicht mit einer tableView-Instanzmethode ausgestattet sind.
(B) liefert also das richtige Ergebnis für alle bisherigen iOS-Versionen und alle zukünftigen, bis sie die Funktionsweise von Ansichten radikal ändern.
Um zu vermeiden, dass verallgemeinerbarer Code immer wieder geschrieben wird, würde ich Folgendes verwenden:
+ (id)enclosingViewOfView:(UIView *)view withClass:(Class)returnKindOfClass {
while (view&&![view isKindOfClass:returnKindOfClass]) view=view.superview;
return(view);
}
und eine bequeme Methode:
+ (UITableView *)tableForCell:(UITableViewCell *)cell {
return([self enclosingViewOfView:cell.superview withClass:UITableView.class]);
}
(oder Kategorien, wenn Sie möchten)
Übrigens, wenn Sie über die Auswirkung einer Schleife mit etwa 20 Iterationen dieser Größe auf die Leistung Ihrer App besorgt sind, tun Sie dies nicht.
Wenn Sie über das Modellobjekt sprechen, das in der Zelle angezeigt wird, dann könnte / sollte dieses Modell definitiv über sein übergeordnetes Modell Bescheid wissen, das verwendet werden kann, um Änderungen in den Tabellen zu finden oder auszulösen, die das Modell der Zelle möglicherweise enthält angezeigt werden in. Dies ist wie (A), jedoch weniger spröde bei zukünftigen iOS-Updates (z. B. kann es vorkommen, dass der UITableViewCell-Wiederverwendungscache eines Tages pro Wiederverwendungskennung und nicht pro Wiederverwendungskennung pro Tabellenansicht an diesem Tag für alle Implementierungen vorhanden ist, die die Schwachen verwenden Referenzmethode wird brechen).
Die Modellmethode wird für Änderungen an den in der Zelle angezeigten Daten verwendet (dh Modelländerungen), da sich Änderungen überall dort ausbreiten, wo das Modell angezeigt wird (z. B. ein anderer UIViewController an einer anderen Stelle in der App, Protokollierung, ...).
Die Zelle Methode würde für Tableview Aktionen verwendet werden, die wahrscheinlich immer eine schlechte Idee wäre , wenn die Zelle nicht einmal ein Subview einer Tabelle ist (obwohl es ist der Code, geht Nüsse).
Verwenden Sie in beiden Fällen einen Komponententest, anstatt davon auszugehen, dass scheinbar sauberer Code nur funktioniert, wenn iOS aktualisiert wird.