dequeueReusableCellWithIdentifierとdequeueReusableCellWithIdentifierを使用する場合:forIndexPath


167

dequeueReusableCellWithIdentifierには2つのオーバーロードがあり、どちらを使用するべきかを判断しようとしていますか?

forIndexPath関数に関するアップルのドキュメントには、「このメソッドはインデックスパスを使用して、テーブルビュー内のセルの位置に基づいて追加の構成を実行します」と記載されています。

それをどのように解釈するのかわかりませんか?

回答:


216

最も重要な違いはforIndexPath:、識別子のクラスまたはnibを登録しなかった場合、バージョンがアサート(クラッシュ)することです。その場合、古い(非forIndexPath:)バージョンが返さnilれます。

registerClass:forCellReuseIdentifier:テーブルビューに送信して、識別子のクラスを登録します。registerNib:forCellReuseIdentifier:テーブルビューに送信して、識別子のnibを登録します。

ストーリーボードにテーブルビューとセルプロトタイプを作成すると、ストーリーボードローダーが、ストーリーボードで定義したセルプロトタイプの登録を処理します。

セッション200-WWDC 2012のCocoa Touchの新機能では、8分forIndexPath:30秒頃に始まる(当時の)バージョンについて説明しています。「常に初期化されたセルを取得する」(クラスまたはnibを登録しないとクラッシュすることは言うまでもありません)と書かれています。

ビデオはまた「それはその索引パスに適切なサイズになるだろう」と述べています。おそらくこれは、テーブルビュー自体の幅を確認し、デリゲートのtableView:heightForRowAtIndexPath:メソッド(定義されている場合)を呼び出すことによって、セルを返す前にセルのサイズを設定することを意味します。 これが、インデックスパスが必要な理由です。


本当に助かります、ありがとう。デキュー時にセルのサイズを設定することは、自動サイズ設定とレイアウトの制約ではあまりメリットがないように見えますか?
ベンジョン2017年

38

dequeueReusableCellWithIdentifier:forIndexPath:、常にセルを返します。既存のセルを再使用するか、新しいセルを作成してセルがない場合は戻ります。

一方、従来型dequeueReusableCellWithIdentifier:は、存在する場合、つまり再利用可能なセルがある場合はセルを返し、それ以外の場合はnilを返します。したがって、nil値をチェックするための条件も作成する必要があります。

はiOS 6 dequeueReusableCellWithIdentifier:以降dequeueReusableCellWithIdentifier:forIndexPathでのみ利用可能であるため、iOS 5以前のバージョンをサポートする場合は、質問に答える

リファレンス:https : //developer.apple.com/library/ios/documentation/uikit/reference/UITableView_Class/Reference/Reference.html#//apple_ref/occ/instm/UITableView/dequeueReusableCellWithIdentifier: forIndexPath


いいえ、常にセルを返すわけではありません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 Interphase [4024:42920390] ***キャッチされない例外 'NSInternalInconsistencyException'によりアプリを終了します、理由: '識別子MyCustomCellIdentifierでセルをデキューできません-nibを登録する必要がありますまたは識別子のクラス、またはストーリーボードのプロトタイプセルを接続する '
clearlight

@binarystar ロードしたビューでカスタムセルのペン先またはクラスを登録する必要あります。のように:[self.tableView registerNib:[UINib nibWithNibName:@"cell" bundle:nil] forCellReuseIdentifier:@"cell"];
GoodSp33d 2014

6

なぜAppleが新しいメソッドdequeueReusableCellWithIdentifier:forIndexPath:を作成したのか理解したことがありません。それらに関するドキュメントは完全ではなく、誤解を招く可能性があります。2つのメソッドを区別できた唯一の違いは、古いメソッドは、渡された識別子を持つセルが見つからない場合はnilを返すことができ、新しいメソッドは返せない場合はクラッシュすることです。細胞。どちらの方法でも、識別子を正しく設定してセルをストーリーボードに作成すると、セルが返されることが保証されます。クラスまたはxibを登録し、コードまたはxibファイルでセルを作成すると、どちらのメソッドもセルを返すことが保証されます。


3
新しいメソッドは、インデックスパスを使用してセルの適切なサイズを決定します。
rob mayoff

1
@robmayoffしかし、これは意味がありますか?新しいメソッドがなくても、セルのサイズを適切に設定できます。新しい方法は便利ですか?
fujianjin6471 2015

1
詳細については、私の回答の最後の段落をお読みください。
rob mayoff 2015

つまり、これは、すべてのセルがテーブル内の同じサイズである場合、どのメソッドを呼び出しても問題ないということですか?
ハッピーハッピー2016年

2
を指定するtableView.estimateHeightと、セルのサイズも適切に決定されます。新しい方法のメリットはまだ得られません。
ライアン

1

略して:

dequeueReusableCell(withIdentifier, for)プロトタイプセルでのみ機能します。プロトタイプセルが存在しない場合に使用しようとすると、アプリがクラッシュします。

Hollemans M. 2016、第2章チェックリスト、IOS実習生(第5版)。pp:156。


-2

動的に生成されたコンテンツを使用している場合は、両方を使用することをお勧めします。そうしないと、アプリが予期せずクラッシュする可能性があります。独自の関数を実装して、オプションの再利用可能なセルを取得できます。そうであれば、nil表示されていない空のセルを返す必要があります。

スウィフト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
    }
}

そして、空のセルを返す拡張:

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

それを使用する方法の完全な例:

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()
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.