Festlegen des Stils von UITableViewCell bei Verwendung von iOS 6 UITableView dequeueReusableCellWithIdentifier: forIndexPath:

81

Ich versuche herauszufinden, wie man das einstellt, UITableViewCellStylewenn man die neuen Methoden in iOS 6 verwendet UITableView.

Früher habe UITableViewCellich beim Erstellen eines die UITableViewCellStyleAufzählung geändert , um beim Aufrufen verschiedene Arten von Standardzellen zu erstellen, initWithStyle:aber soweit ich das beurteilen kann, ist dies nicht mehr der Fall.

Die Apple-Dokumentation für UITableViewStaaten:

Rückgabewert : Ein UITableViewCell-Objekt mit der zugehörigen Wiederverwendungskennung. Diese Methode gibt immer eine gültige Zelle zurück.

Diskussion : Aus Leistungsgründen sollte die Datenquelle einer Tabellenansicht UITableViewCell-Objekte im Allgemeinen wiederverwenden, wenn sie Zellen in ihrer tableView: cellForRowAtIndexPath: -Methode Zellen zuweist. Eine Tabellenansicht verwaltet eine Warteschlange oder Liste von UITableViewCell-Objekten, die die Datenquelle zur Wiederverwendung markiert hat. Rufen Sie diese Methode von Ihrem Datenquellenobjekt aus auf, wenn Sie aufgefordert werden, eine neue Zelle für die Tabellenansicht bereitzustellen. Diese Methode entfernt eine vorhandene Zelle aus der Warteschlange, wenn eine verfügbar ist, oder erstellt eine neue Zelle basierend auf der zuvor registrierten Klassen- oder NIB-Datei.

Wichtig : Sie müssen eine Klassen- oder NIB-Datei mit der Methode registerNib: forCellReuseIdentifier: oder registerClass: forCellReuseIdentifier: registrieren, bevor Sie diese Methode aufrufen.

Wenn Sie eine Klasse für den angegebenen Bezeichner registriert haben und eine neue Zelle erstellt werden muss, initialisiert diese Methode die Zelle durch Aufrufen ihrer Methode initWithStyle: reuseIdentifier :. Bei nib-basierten Zellen lädt diese Methode das Zellenobjekt aus der bereitgestellten nib-Datei. Wenn eine vorhandene Zelle zur Wiederverwendung verfügbar war, ruft diese Methode stattdessen die prepareForReuse-Methode der Zelle auf.

So sieht mein neues cellForRowAtIndexPathnach der Implementierung der neuen Methoden aus:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"cell_identifier";

    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    return cell;
}

Der Code, den ich bisher habe, funktioniert einwandfrei, gibt aber immer den Standardstil zurück. Wie kann ich das ändern , damit ich Zellen mit den anderen Stilen wie schaffen kann UITableViewCellStyleDefault, UITableViewCellStyleValue1, UITableViewCellStyleValue2und UITableViewCellStyleSubtitle?

Ich möchte keine Unterklasse erstellen UITableViewCell, sondern nur den Standardtyp ändern, wie ich es vor iOS 6 tun konnte. Es scheint seltsam, dass Apple erweiterte Methoden bereitstellt, jedoch mit minimaler Dokumentation, um deren Implementierung zu unterstützen.

Hat jemand dies gemeistert oder ist er auf ein ähnliches Problem gestoßen? Ich habe Mühe, überhaupt vernünftige Informationen zu finden.

Captain Redmuff
quelle

Antworten:

105

Ich weiß, dass Sie gesagt haben, Sie wollten keine Unterklasse erstellen, aber es sieht unvermeidlich aus. Erstellt basierend auf dem Assemblycode beim Testen im iOS 6.0-Simulator durch Ausführen UITableViewneue Instanzen UITableViewCell(oder deren Unterklassen)

[[<RegisteredClass> alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:<ReuseIdentifier>]

Mit anderen Worten, der Stil sent ( UITableViewCellStyleDefault) scheint fest codiert zu sein. Um dies zu umgehen, müssen Sie eine Unterklasse erstellen, die den Standardinitialisierer überschreibt und den gewünschten initWithStyle:reuseIdentifier:Stil übergibt:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    // ignore the style argument, use our own to override
    self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier];
    if (self) {
        // If you need any further customization
    }
    return self;
}

Auch könnte es besser sein , senden registerClass:forCellReuseIdentifier:in viewDidLoad, anstatt sie jedes Mal , wenn eine Zelle tun wird gebeten:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.tableView registerClass:<RegisteredClass> forCellReuseIdentifier:<ReuseIdentifier>];
}
Bolot
quelle
4
Ich begann anzunehmen, dass dies tatsächlich der Fall sein würde. Es ist kein großes Problem, aber eine Unterklasse zu benötigen UITableViewCell, um die anderen Standardstile zu erhalten, ist ein Problem, da nur unnötige Dateien erstellt werden. Vielen Dank für Ihren Kommentar und die Bestätigung meines Verdachts.
Captain Redmuff
11
Vergessen Sie nicht, dass Sie anstelle von Unterklassen die alte iOS5-Methode verwenden können, die immer noch gültig ist. Auf diese Weise können Sie jede Art von Zellenstil initialisieren, die Sie selbst möchten. Siehe die andere Antwort.
SpacyRicochet
60

dequeueReusableCellWithIdentifierist nicht veraltet, sodass Sie das neue nicht verwenden müssen dequeueReusableCellWithIdentifier:forIndexPath:.

Verwenden Sie den neuen Weg zusammen mit der entsprechenden Registermethode (in viewDidLoad), wenn Sie eine benutzerdefinierte Zellenklasse verwenden, aber verwenden Sie den alten Weg, wenn Sie eine der UITableViewCellStyle-Aufzählungen verwenden möchten.

Murray Sagal
quelle
1
Upvoted für den Hinweis auf , dass Sie nicht haben , um die Phantasie neue Methoden. Nur wenn sie Ihrem Zweck entsprechen oder wenn die Alternativen veraltet sind.
SpacyRicochet
Wenn Sie besonders interessiert sind, können Sie diese überschreiben dequeueReusableCellWithIdentifier:forIndexPath:, um einige Kennungen bereitzustellen, die Zellen auf die alte Weise erstellen (und zurückgeben). Andere Bezeichner rufen super auf und geben das zurück. Es kann sinnvoll sein, NSDictionaryBezeichner für Konstruktorblöcke für diese Art von Bezeichnern zu haben.
Benjohn
11

Sie können eine überflüssige Unterklasse vermeiden, indem Sie den Storyboard Interface Builder verwenden:

  1. Wählen Sie in der Storyboard-Ansicht die Zellenprototypzelle der Tabellenansicht aus (in der Tabellenansicht).
  2. Ändern Sie in der Ansicht Dienstprogramme im Inspektor Attribute den Stilwert
  3. (Optional) Ändern Sie andere Werte wie Auswahl und Zubehör

Das neue iOS 6.0 dequeueReusableCellWithIdentifier:forIndexPath:verwendet diese Werte, wenn neue Zellen zugewiesen und zurückgegeben werden. (Getestet auf einer iOS 6.0-Kompilierung mit Xcode 4.5.2)

Jeff Collier
quelle
7

Eine andere Alternative, die eine Datei speichert, besteht darin, eine Schreibfeder zu erstellen und registerNib:forCellReuseIdentifier:stattdessen zu verwenden.

Das Erstellen der Feder ist einfach: Erstellen Sie eine neue .xib-Datei in Interface Builder. Löschen Sie die Standardansicht. Fügen Sie ein Zellenobjekt für die Tabellenansicht hinzu. Ändern Sie im Attributinspektor den Stil für die Zelle. (Hier haben Sie auch die Möglichkeit, die Zelle weiter anzupassen, indem Sie andere Attribute anpassen.)

viewDidLoadRufen Sie dann in der Methode Ihres Table View Controllers Folgendes auf:

[self.tableView registerNib:[UINib nibWithNibName:@"StyleSubtitleTableCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"Cell"];
Herr Berna
quelle
initWithStyle: reuseIdentifier wird nicht aufgerufen.
Thierryb
0

Bolots Antwort ist die richtige. Einfach und Sie müssen keine XIB-Datei erstellen.

Ich wollte nur seine Antwort für jeden aktualisieren, der es mit Swift anstelle von Objective-C macht:

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: .value1, reuseIdentifier: reuseIdentifier)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
Gabriel Oliva
quelle
-5

Meine Lösung besteht darin, anzurufen, initWithStyle: reuseIdentifier:nachdem ich es mit erhalten habe [self.tableView dequeueReusableCellWithIdentifier:@"cellId" forIndexPath:indexPath]. Immerhin initist es nur ein weiterer Selektor, und der Compiler macht keine Einschränkungen beim Aufrufen eines bereits initialisierten Objekts. Es wird sich jedoch darüber beschweren, dass das Ergebnis des Aufrufs von init nicht verwendet wird, also mache ich:

UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"cellId" forIndexPath:indexPath];
cell = [cell initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cellId"];

Ich kann mir vorstellen, dass dies in Swift nicht funktioniert ...

Chris
quelle
Eleganteste Lösung imo. Hoffentlich schafft der Mut von initWithStyle nicht alles neu.
Scott Birksted
2
Nun, ich denke, wenn du es so machst, kannst du das Dequeuing-Zeug ganz fallen lassen ...
stk
1
Die Wiederverwendung von Zellen ist der Schlüssel zu einer performanten UITableView. Ihre Lösung schlägt vor, Zellen nicht wiederzuverwenden.
Berik
2
Wenn Sie initWithStyle: reuseIdentifierdas zweite Mal aufrufen , überschreiben Sie die Zelle tatsächlich mit einem neu erstellten Objekt. Ja, die Zuweisung des Speichers wurde bereits vorgenommen, und die neue Zelle wird denselben Speicherort überschreiben. Sie erstellen jedoch tatsächlich ein völlig neues Objekt, wenn Sie es erneut initialisieren. Dies negiert die gesamte Optimierung, die den Sinn der Wiederverwendung von Zellen ausmacht.
AnthonyMDev
1
Keine gute Lösung - wenn Sie diese Lösung verwenden, ist es meiner Meinung nach zumindest besser, die Zellen vollständig aus der
Warteschlange