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ć?

Jaja Harris
źródło

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.

rob mayoff
źródło
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 :

GoodSp33d
źródło
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.

rdelmar
źródło
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.

SLN
źródło
-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()
    }
}
hhamm
źródło