Kapan menggunakan dequeueReusableCellWithIdentifier vs dequeueReusableCellWithIdentifier: forIndexPath

167

Ada dua kelebihan untuk dequeueReusableCellWithIdentifier dan saya mencoba menentukan kapan saya harus menggunakan satu vs yang lain?

Dokumen apple mengenai fungsi forIndexPath menyatakan, "Metode ini menggunakan jalur indeks untuk melakukan konfigurasi tambahan berdasarkan posisi sel dalam tampilan tabel."

Saya tidak yakin bagaimana menafsirkannya?

Jaja Harris
sumber

Jawaban:

216

Perbedaan yang paling penting adalah bahwa forIndexPath:versi menegaskan (lumpuh) jika Anda tidak mendaftarkan kelas atau pena untuk pengidentifikasi. Versi yang lebih lama (non- forIndexPath:) kembali nildalam kasus itu.

Anda mendaftarkan kelas untuk pengidentifikasi dengan mengirim registerClass:forCellReuseIdentifier:ke tampilan tabel. Anda mendaftarkan pena untuk pengidentifikasi dengan mengirim registerNib:forCellReuseIdentifier:ke tampilan tabel.

Jika Anda membuat tampilan tabel dan prototipe sel Anda di storyboard, loader storyboard akan mengurus pendaftaran prototipe sel yang Anda definisikan di storyboard.

Sesi 200 - Apa yang Baru di Cocoa Touch dari WWDC 2012 membahas versi (yang baru) forIndexPath:mulai sekitar 8m30-an. Dikatakan bahwa “Anda akan selalu mendapatkan sel yang diinisialisasi” (tanpa menyebutkan bahwa itu akan macet jika Anda tidak mendaftar kelas atau nib).

Video itu juga mengatakan bahwa "itu akan menjadi ukuran yang tepat untuk jalur indeks itu". Agaknya ini berarti bahwa ia akan mengatur ukuran sel sebelum mengembalikannya, dengan melihat lebar tampilan tabel itu sendiri dan memanggil tableView:heightForRowAtIndexPath:metode delegasi Anda (jika ditentukan). Inilah sebabnya mengapa perlu jalur indeks.

rob mayoff
sumber
Itu sangat membantu, terima kasih. Memiliki ukuran sel pada waktu dequeue tampaknya kurang menguntungkan dengan ukuran otomatis dan kendala tata letak?
Benjohn
38

dequeueReusableCellWithIdentifier:forIndexPath:akan selalu mengembalikan sel. Entah itu menggunakan kembali sel yang ada atau membuat yang baru dan kembali jika tidak ada sel.

Sementara, tradisional dequeueReusableCellWithIdentifier:akan mengembalikan sel jika ada yaitu jika ada sel yang dapat digunakan kembali mengembalikan yang lain itu mengembalikan nihil. Jadi, Anda harus menulis ketentuan untuk memeriksa nilnilai juga.

Untuk menjawab pertanyaan Anda gunakan dequeueReusableCellWithIdentifier:ketika Anda ingin mendukung iOS 5 dan versi yang lebih rendah karena dequeueReusableCellWithIdentifier:forIndexPathhanya tersedia di iOS 6+

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

GoodSp33d
sumber
Tidak, itu tidak selalu mengembalikan sel 2014-12-26 07: 56: 39.947 testProg [4024: 42920390] *** Kegagalan pernyataan dalam - [UITableView dequeueReusableCellWithIdentifier: forIndexPath:], /SourceCache/UIKit_Sim/UIKit-3318.65/ UITableView.m: 6116 2014-12-26 07: 56: 39.954 Interphase [4024: 42920390] *** Mengakhiri aplikasi karena pengecualian tanpa peringatan 'NSInternalInconsistencyException', alasan: 'tidak dapat membuat sel dengan pengenal MyCustomCellIdentifier - harus mendaftarkan nib atau kelas untuk pengidentifikasi atau menghubungkan sel prototipe dalam storyboard '
clearlight
@ binarystar Anda harus mendaftarkan nib atau kelas sel khusus Anda agar dapat memuat. seperti:[self.tableView registerNib:[UINib nibWithNibName:@"cell" bundle:nil] forCellReuseIdentifier:@"cell"];
GoodSp33d
6

Saya tidak pernah mengerti mengapa Apple menciptakan metode yang lebih baru, dequeueReusableCellWithIdentifier: forIndexPath :. Dokumentasi mereka tentang mereka tidak lengkap, dan agak menyesatkan. Satu-satunya perbedaan yang saya dapat membedakan antara kedua metode, adalah bahwa metode yang lebih lama dapat mengembalikan nihil, jika tidak menemukan sel dengan pengenal yang dilewati, sedangkan metode yang lebih baru lumpuh, jika tidak dapat kembali sebuah sel. Kedua metode dijamin untuk mengembalikan sel, jika Anda telah menetapkan pengidentifikasi dengan benar, dan membuat sel dalam storyboard. Kedua metode juga dijamin untuk mengembalikan sel jika Anda mendaftarkan kelas atau xib, dan membuat sel Anda dalam kode atau file xib.

rdelmar
sumber
3
Metode baru menggunakan jalur indeks untuk menentukan ukuran yang tepat untuk sel.
rob mayoff
1
@robmayoff Tapi apakah ini masuk akal? Tanpa metode baru, ukuran sel masih dapat diatur dengan benar. Bisakah metode baru ini menawarkan kenyamanan?
fujianjin6471
1
Baca paragraf terakhir dari jawaban saya untuk detailnya.
rob mayoff
Jadi apakah ini berarti bahwa, jika semua sel saya memiliki ukuran yang sama dalam tabel, tidak masalah metode apa yang saya panggil?
Happiehappie
2
Jika saya berikan tableView.estimateHeight, ukuran sel juga akan ditentukan dengan benar. Saya masih belum mendapatkan manfaat dari metode baru ini.
Ryan
1

Singkatnya:

dequeueReusableCell(withIdentifier, for)hanya bekerja dengan sel prototipe. Jika Anda mencoba menggunakannya ketika sel prototipe tidak ada, itu akan merusak aplikasi.

Hollemans M. 2016, Bab 2 Daftar Periksa, Apprentice IOS (Edisi 5). hal: 156.

SLN
sumber
-2

Saya akan merekomendasikan untuk menggunakan keduanya jika Anda menggunakan konten yang dihasilkan dinamis. Kalau tidak, aplikasi Anda mungkin mogok secara tak terduga. Anda bisa menerapkan fungsi Anda sendiri untuk mengambil sel yang dapat digunakan kembali opsional. Jika ya, nilAnda harus mengembalikan sel kosong yang tidak terlihat:

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

Dan ekstensi untuk mengembalikan sel kosong:

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

Contoh lengkap cara menggunakannya:

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
sumber