2014-09-13 10 views
124

Esistono due sovraccarichi per dequeueReusableCellWithIdentifier e sto cercando di determinare quando dovrei usare uno vs l'altro?Quando utilizzare dequeueReusableCellWithIdentifier vs dequeueReusableCellWithIdentifier: forIndexPath

I documenti Apple relativi alla funzione forIndexPath indica, "Questo metodo utilizza il percorso dell'indice per eseguire un'ulteriore configurazione in base alla posizione della cella nella vista tabella."

Non so come interpretarlo?

risposta

164

La differenza più importante è che la versione forIndexPath: asserisce (si blocca) se non hai registrato una classe o pennino per l'identificatore. In questo caso, la versione precedente (non forIndexPath:) restituisce nil.

Si registra una classe per un identificatore inviando registerClass:forCellReuseIdentifier: alla vista tabella. Si registra un pennino per un identificatore inviando registerNib:forCellReuseIdentifier: alla vista tabella.

Se si crea la vista tabella ei prototipi di cella in uno storyboard, il caricatore dello storyboard si occupa di registrare i prototipi di cella definiti nello storyboard.

Session 200 - What's New in Cocoa Touch from WWDC 2012 discute la (quindi nuova) versione forIndexPath: a partire da circa 8m30s. Dice che "avrai sempre una cella inizializzata" (senza menzionare che si bloccherà se non hai registrato una classe o un pennino).

Il video dice anche che "sarà la dimensione giusta per quel percorso dell'indice". Presumibilmente ciò significa che imposterà la dimensione della cella prima di restituirla, osservando la larghezza della vista tabella e chiamando il metodo tableView:heightForRowAtIndexPath: del delegato (se definito). Ecco perché ha bisogno del percorso dell'indice.

+0

Questo è davvero utile, grazie. Avere le dimensioni della cella al momento della cancellazione sembra meno vantaggioso con il dimensionamento automatico e i vincoli di layout? – Benjohn

6

Non ho mai capito perché Apple ha creato il metodo più recente, dequeueReusableCellWithIdentifier: forIndexPath :. La loro documentazione su di loro non è completa ed è in qualche modo fuorviante. L'unica differenza che sono riuscito a distinguere tra i due metodi è che quel metodo più vecchio può restituire nil, se non trova una cella con l'identificatore passato, mentre il metodo più recente si blocca, se non può restituirlo una cellula. Entrambi i metodi sono garantiti per restituire una cella, se è stato impostato correttamente l'identificativo e creato la cella in uno storyboard. Entrambi i metodi sono inoltre garantiti per restituire una cella se si registra una classe o uno xib e si crea la cella nel codice o in un file xib.

+2

Il nuovo metodo utilizza il percorso dell'indice per determinare la dimensione corretta per la cella. –

+0

@robmayoff Ma ha senso? Senza il nuovo metodo, la dimensione della cella può ancora essere impostata correttamente. Il nuovo metodo può offrire qualche comodità? – fujianjin6471

+1

Leggi l'ultimo paragrafo della mia risposta per i dettagli. –

30

dequeueReusableCellWithIdentifier:forIndexPath:sempre restituire una cella. Re utilizza celle esistenti o ne crea una nuova e restituisce se non ci sono celle.

Mentre, il tradizionale dequeueReusableCellWithIdentifier: restituirà una cella se esiste i.e se c'è una cella che può essere riutilizzata restituisce che altrimenti restituisce nil. Quindi dovresti scrivere una condizione per verificare il valore nil.

Per rispondere alla tua domanda utilizzare dequeueReusableCellWithIdentifier: quando si desidera supportare iOS 5 e versioni più bassi dal dequeueReusableCellWithIdentifier:forIndexPath è disponibile solo su iOS 6+

Riferimento: https://developer.apple.com/library/ios/documentation/uikit/reference/UITableView_Class/Reference/Reference.html#//apple_ref/occ/instm/UITableView/dequeueReusableCellWithIdentifier:forIndexPath:

+0

No, non * sempre * restituisce una cella 2014-12-26 07: 56: 39.947 testProg [4024: 42920390] *** Errore asserzione in - [UITableView dequeueReusableCellWithIdentifier: forIndexPath:],/SourceCache/UIKit_Sim/UIKit -3318.65/UITableView.m: 6116 2014-12-26 07: 56: 39,954 Interphase [4024: 42920390] *** Termina l'applicazione a causa dell'eccezione non rilevata 'NSInternalInconsistencyException', motivo: 'impossibile rimuovere una cella con identificativo MyCustomCellIdentifier - è necessario registrare un pennino o una classe per l'identificatore o collegare una cella prototipo in uno storyboard ' – clearlight

+0

@binarystar È * necessario * registrare un pennino o una classe della cella personalizzata nella visualizzazione caricata. come: '[self.tableView registerNib: [UINib nibWithNibName: @" cell "bundle: nil] forCellReuseIdentifier: @" cell "];' – GoodSp33d

0

Si consiglia di utilizzare entrambi se si utilizza il contenuto generato dinamicamente. Altrimenti la tua app potrebbe bloccarsi in modo imprevisto. È possibile implementare la propria funzione per recuperare una cella riutilizzabile opzionale.Se è nil si dovrebbe tornare una cella vuota che non è visibile:

Swift 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 
    } 
} 

e l'estensione per restituire una cella vuota:

// 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 
    } 
} 

un esempio completo di come usarlo:

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() 
    } 
} 
0

Per short:

dequeueReusableCell(withIdentifier, for) funziona solo con le celle del prototipo . Se si è tentato di utilizzarlo quando la cella del prototipo è assente, si arresterebbe in modo anomalo.

Hollemans M. 2016, Capitolo 2 Lista di controllo, IOS Apprentice (5th Edition). pp: 156.

Problemi correlati