Kiedy używać dequeueReusableCellWithIdentifier vs dequeueReusableCellWithIdentifier: forIndexPath


167

Istnieją dwa przeciążenia dla dequeueReusableCellWithIdentifier i próbuję określić, kiedy powinienem używać jednego, a kiedy drugiego?

Dokumentacja firmy apple dotycząca funkcji forIndexPath stwierdza: „Ta metoda wykorzystuje ścieżkę indeksu do wykonania dodatkowej konfiguracji na podstawie pozycji komórki w widoku tabeli”.

Nie jestem jednak pewien, jak to zinterpretować?

Odpowiedzi:


216

Najważniejszą różnicą jest to, że forIndexPath:wersja potwierdza (ulega awarii), jeśli nie zarejestrowałeś klasy lub końcówki dla identyfikatora. W takim przypadku forIndexPath:zwracana jest starsza (nie ) wersja nil.

Rejestrujesz klasę dla identyfikatora, wysyłając registerClass:forCellReuseIdentifier:ją do widoku tabeli. Zarejestruj końcówkę dla identyfikatora, wysyłając registerNib:forCellReuseIdentifier:ją do widoku tabeli.

Jeśli utworzysz widok tabeli i prototypy komórek w serii ujęć, moduł ładujący scenorys zajmie się rejestracją prototypów komórek, które zdefiniowałeś w serii ujęć.

Sesja 200 - Co nowego w Cocoa Touch z WWDC 2012 omawia (wówczas nową) forIndexPath:wersję zaczynającą się od około 8 min 30 s. Mówi, że „zawsze otrzymasz zainicjowaną komórkę” (nie wspominając, że ulegnie awarii, jeśli nie zarejestrujesz klasy lub stalówki).

Film mówi również, że „będzie to odpowiedni rozmiar dla tej ścieżki indeksu”. Prawdopodobnie oznacza to, że ustawi rozmiar komórki przed jej zwróceniem, patrząc na własną szerokość widoku tabeli i wywołując tableView:heightForRowAtIndexPath:metodę delegata (jeśli została zdefiniowana). Dlatego potrzebuje ścieżki indeksu.


To bardzo pomocne, dzięki. Posiadanie rozmiaru komórki w czasie usuwania z kolejki wydaje się mniej korzystne w przypadku automatycznego rozmiaru i ograniczeń układu?
Benjohn

38

dequeueReusableCellWithIdentifier:forIndexPath:będzie zawsze wrócić komórkę. Wykorzystuje ponownie istniejące komórki lub tworzy nowe i zwraca, jeśli nie ma żadnych komórek.

Podczas gdy tradycyjny dequeueReusableCellWithIdentifier:zwróci komórkę, jeśli istnieje, tj. Jeśli istnieje komórka, której można użyć ponownie, zwraca, w przeciwnym razie zwraca zero. Musiałbyś więc napisać warunek, aby również sprawdzić nilwartość.

Aby odpowiedzieć na twoje pytanie, użyj, dequeueReusableCellWithIdentifier:gdy chcesz obsługiwać iOS 5 i niższe wersje, ponieważ dequeueReusableCellWithIdentifier:forIndexPathjest dostępny tylko na iOS 6+

Źródła: https://developer.apple.com/library/ios/documentation/uikit/reference/UITableView_Class/Reference/Reference.html#//apple_ref/occ/instm/UITableView/dequeueReusableCellWithIdentifier:forIndexPath :


Nie, nie zawsze zwraca komórkę 26.12.2014 07: 56: 39.947 testProg [4024: 42920390] *** Błąd potwierdzenia w - [UITableView dequeueReusableCellWithIdentifier: forIndexPath:], /SourceCache/UIKit_Sim/UIKit-3318.65/ UITableView.m: 6116 2014-12-26 07: 56: 39.954 Interphase [4024: 42920390] *** Zakończenie aplikacji z powodu nieprzechwyconego wyjątku „NSInternalInconsistencyException”, powód: „nie można usunąć z kolejki komórki z identyfikatorem MyCustomCellIdentifier - należy zarejestrować końcówkę lub klasa dla identyfikatora lub połącz prototypową komórkę w scenorysie '
jasne światło

@binarystar Państwo musi zarejestrować stalówki lub klasę niestandardowego komórki w widoku nie obciążenie. na przykład:[self.tableView registerNib:[UINib nibWithNibName:@"cell" bundle:nil] forCellReuseIdentifier:@"cell"];
GoodSp33d

6

Nigdy nie zrozumiałem, dlaczego Apple stworzył nowszą metodę, dequeueReusableCellWithIdentifier: forIndexPath :. Ich dokumentacja nie jest kompletna i jest nieco myląca. Jedyną różnicą, jaką udało mi się dostrzec między tymi dwiema metodami, jest to, że starsza metoda może zwrócić zero, jeśli nie znajdzie komórki z przekazanym identyfikatorem, podczas gdy nowsza metoda ulega awarii, jeśli nie może zwrócić komórka. Obie metody gwarantują zwrócenie komórki, jeśli poprawnie ustawiłeś identyfikator i utworzysz komórkę w serii ujęć. Obie metody gwarantują również zwrócenie komórki, jeśli zarejestrujesz klasę lub xib i utworzysz komórkę w kodzie lub pliku xib.


3
Nowa metoda wykorzystuje ścieżkę indeksu do określenia odpowiedniego rozmiaru komórki.
rob mayoff

1
@robmayoff Ale czy to ma sens? Bez nowej metody rozmiar komórki nadal można ustawić prawidłowo. Czy nowa metoda może być wygodna?
fujianjin6471

1
Przeczytaj ostatni akapit mojej odpowiedzi, aby poznać szczegóły.
rob mayoff

Czy to oznacza, że ​​jeśli wszystkie moje komórki w tabeli mają takie same rozmiary, nie ma znaczenia, którą metodę wywołuję?
Happiehappie

2
Jeśli podam tableView.estimateHeight, rozmiar komórki również zostanie prawidłowo określony. Nadal nie czerpię korzyści z nowej metody.
Ryan

1

W skrócie:

dequeueReusableCell(withIdentifier, for)działa tylko z komórkami prototypowymi. Jeśli spróbujesz go użyć, gdy prototypowa komórka jest nieobecna, aplikacja spowoduje awarię.

Hollemans M. 2016, Rozdział 2 Lista kontrolna, IOS Apprentice (5th Edition). pp: 156.


-2

Zalecałbym użycie obu, jeśli korzystasz z dynamicznie generowanych treści. W przeciwnym razie aplikacja może nieoczekiwanie ulec awarii. Możesz zaimplementować własną funkcję pobierania opcjonalnej komórki wielokrotnego użytku. Jeśli tak nil, powinieneś zwrócić pustą komórkę, która nie jest widoczna:

Szybki 3

// Extensions to UITableView
extension UITableView
{
    // returns nil, if identifier does not exist. 
    // Otherwise it returns a configured cell for the given index path
    open func tryDequeueReusableCell (
        withIdentifier identifier: String, 
        for indexPath: IndexPath) -> UITableViewCell?
    {
        let cell = self.dequeueReusableCell(withIdentifier: identifier)
        if cell != nil {
            return self.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
        }  
        return nil
    }
}

Oraz rozszerzenie zwracające pustą komórkę:

// Extension to UITableViewCell
extension UITableViewCell
{
    // Generates an empty table cell that is not visible
    class func empty() -> UITableViewCell
    {
        let emptyCell = UITableViewCell(frame:CGRect(x:0, y:0, width:0, height:0))
        emptyCell.backgroundColor = UIColor.clear
        return emptyCell
    }
}

Kompletny przykład, jak go używać:

import Foundation
import UIKit

// A protocol is used to identify if we can configure
// a cell with CellData
protocol ConfigureAbleWithCellData
{
    func configure(_ data: CellData)
}

class MyCustomTableViewCell :
    UITableViewCell,
    ConfigureAbleWithCellData
{
    @IBOutlet weak var title:UILabel! = nil
    func configure(_ data: CellData)
    {
        self.title.text = data.title
    }
}

// This actually holds the data for one cell
struct CellData
{
    var title:String = ""
    var reusableId:String = ""
}

class CosmoConverterUnitTableViewController:
    UIViewController,
    UITableViewDelegate,
    UITableViewDataSource
{
    // Storage
    var data = Array<Array<CellData>>()

    func loadData()
    {
        var section1:[CellData] = []
        var section2:[CellData] = []

        section1.append(CellData(title:"Foo", reusableId:"cellType1"))
        section2.append(CellData(title:"Bar", reusableId:"cellType2"))

        data.append(section1)
        data.append(section2)
    }

    func tableView(_ tableView: UITableView,
                   numberOfRowsInSection section: Int) -> Int
    {
        return data[section].count
    }

    public func numberOfSections(in tableView: UITableView) -> Int
    {
        return data.count
    }

    func tableView(
        _ tableView: UITableView,
        cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        guard
            indexPath.row < data[indexPath.section].count
            else
        {
            fatalError("this can't be")
        }

        let cellData = data[indexPath.section][indexPath.row]

        if let cell = tableView.tryDequeueReusableCell(
            withIdentifier: cellData.reusableId,
            for: indexPath)
        {
            if let configurableCell = cell as? ConfigureAbleWithCellData
            {
                configurableCell.configure(cellData)
            }
            else
            {
                // cell is not of type ConfigureAbleWithCellData
                // so we cant configure it.
            }
            return cell
        }
        // id does not exist
        return UITableViewCell.empty()
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.