DequeueReusableCellWithIdentifier vs dequeueReusableCellWithIdentifier: forIndexPath ne zaman kullanılır?


167

DequeueReusableCellWithIdentifier için iki aşırı yüklenme var ve ne zaman diğerine karşı kullanmalıyım?

Apple forIndexPath işleviyle ilgili dokümanlar "Bu yöntem, hücrenin tablo görünümündeki konumuna dayalı olarak ek yapılandırma gerçekleştirmek için dizin yolunu kullanır."

Bunu nasıl yorumlayacağından emin değilim?

Yanıtlar:


216

En önemli fark, forIndexPath:tanımlayıcı için bir sınıf veya uç kaydetmediyseniz sürümün ileri sürülmesi (çökmesi). Bu durumda eski (olmayan forIndexPath:) sürüm geri döner nil.

registerClass:forCellReuseIdentifier:Tablo görünümüne göndererek tanımlayıcı için bir sınıf kaydedersiniz . registerNib:forCellReuseIdentifier:Tablo görünümüne göndererek tanımlayıcı için bir uç kaydedersiniz .

Tablo görünümünüzü ve hücre prototiplerinizi bir storyboard'da oluşturursanız, storyboard yükleyici, storyboard'da tanımladığınız hücre prototiplerini kaydetmeye özen gösterir.

Oturum 200 - WWDC 2012'den Cocoa Touch'takiforIndexPath: Yenilikler 8m30'lardan başlayarak (o zaman yeni) versiyonu tartışıyor. “Her zaman başlatılmış bir hücre alacaksınız” der (bir sınıfı veya ucu kaydetmediyseniz çökeceğini belirtmeden).

Video ayrıca “bu dizin yolu için doğru boyutta olacak” diyor. Muhtemelen bu, tablo görünümünün kendi genişliğine bakarak ve temsilcinizin tableView:heightForRowAtIndexPath:yöntemini (tanımlanmışsa) çağırarak, döndürmeden önce hücrenin boyutunu ayarlayacağı anlamına gelir . Bu yüzden dizin yoluna ihtiyacı var.


Bu gerçekten faydalı, teşekkürler. Hücrenin dequeue zamanında boyutlandırılması, otomatik boyutlandırma ve yerleşim kısıtlamaları ile daha az avantaj sağlar mı?
Benjohn

38

dequeueReusableCellWithIdentifier:forIndexPath:her zaman bir hücre döndürür. Mevcut hücreleri kullanır veya yeni bir hücre oluşturur ve hücre yoksa geri döner.

Geleneksel dequeueReusableCellWithIdentifier:ise bir hücreyi varsa geri döndürür, yani yeniden kullanılabilecek bir hücre varsa başka bir şekilde sıfır döndürür. Bu yüzden nildeğeri kontrol etmek için bir koşul yazmanız gerekir .

Sorunuzu cevaplamak için , yalnızca iOS 6 dequeueReusableCellWithIdentifier:ve sonraki sürümlerde dequeueReusableCellWithIdentifier:forIndexPathkullanılabildiği için iOS 5 ve daha düşük sürümlerini desteklemek istediğinizde kullanın

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


Hayır, her zaman bir hücre döndürmez 2014-12-26 07: 56: 39.947 testProg [4024: 42920390] *** - [UITableView dequeueReusableCellWithIdentifier: forIndexPath:], /SourceCache/UIKit_Sim/UIKit-3318.65/ UITableView.m: 6116 2014-12-26 07: 56: 39.954 Ara faz [4024: 42920390] *** Yakalanmayan istisna nedeniyle 'NSInternalInconsistencyException' nedeniyle uygulama sonlandırılamıyor - bir uç kaydedilemiyor veya tanımlayıcı için bir sınıf veya bir storyboard'a bir prototip hücre bağlayın '
Clearlight

@binarystar Sen gerekir yük yaptığını görünümünde özel hücrenin bir kalem ucu veya sınıf kaydetmek. gibi:[self.tableView registerNib:[UINib nibWithNibName:@"cell" bundle:nil] forCellReuseIdentifier:@"cell"];
GoodSp33d

6

Apple neden daha yeni bir yöntem, dequeueReusableCellWithIdentifier: forIndexPath: oluşturduğunu hiç anlamadım. Onlarla ilgili belgeleri tam değildir ve bir şekilde yanıltıcıdır. İki yöntem arasında fark edebildiğim tek fark, eski yöntemin tanımlayıcıya sahip bir hücre bulamaması durumunda nil döndürebilmesi, daha yeni yöntem dönmemesi durumunda çökmesidir. bir hücre. Tanımlayıcıyı doğru ayarladıysanız ve hücreyi bir storyboard'da oluşturduysanız, her iki yöntemin de bir hücreyi döndürmesi garanti edilir. Bir sınıf veya xib kaydederseniz ve hücrenizi kodda veya xib dosyasında yaparsanız her iki yöntemin de bir hücre döndürmesi garanti edilir.


3
Yeni yöntem, hücre için uygun boyutu belirlemek üzere dizin yolunu kullanır.
rob mayoff

1
@robmayoff Ama bunun bir anlamı var mı? Yeni yöntem olmadan, hücrenin boyutu yine de düzgün bir şekilde ayarlanabilir. Yeni yöntem herhangi bir kolaylık sağlayabilir mi?
fujianjin6471

1
Ayrıntılar için cevabımın son paragrafını okuyun.
rob mayoff

Bu, tüm hücrelerimin tabloda aynı boyutlara sahip olması durumunda, hangi yöntemi çağırdığımın önemi olmadığı anlamına mı geliyor?
Happiehappie

2
Sağlarsam tableView.estimateHeight, hücrenin boyutu da doğru şekilde belirlenir. Hala yeni yöntemden faydalanamıyorum.
Ryan

1

Kısaca:

dequeueReusableCell(withIdentifier, for)sadece prototip hücrelerle çalışır. Prototip hücre yokken kullanmaya çalıştıysanız, uygulama çökecektir.

Hollemans M. 2016, Bölüm 2 Kontrol Listesi, IOS Çırağı (5. Baskı). sf: 156.


-2

Dinamik olarak oluşturulan içerik kullanıyorsanız her ikisini de kullanmanızı öneririm. Aksi takdirde uygulamanız beklenmedik şekilde kilitlenebilir. İsteğe bağlı bir yeniden kullanılabilir hücre almak için kendi işlevinizi uygulayabilirsiniz. Öyleyse, nilgörünmeyen boş bir hücre döndürmelisiniz:

Hızlı 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
    }
}

Ve boş bir hücre döndürecek uzantı:

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

Nasıl kullanılacağına dair tam bir örnek:

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()
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.