Коли використовувати dequeueReusableCellWithIdentifier vs dequeueReusableCellWithIdentifier: forIndexPath


167

Для dequeueReusableCellWithIdentifier є дві перевантаження, і я намагаюся визначити, коли я повинен використовувати один проти іншого?

Документи Apple щодо функції forIndexPath зазначають: "Цей метод використовує шлях індексу для виконання додаткової конфігурації на основі позиції комірки у поданні таблиці".

Я не знаю, як це інтерпретувати?

Відповіді:


216

Найголовніша відмінність полягає в тому, що forIndexPath:версія стверджує (збої), якщо ви не зареєстрували клас або нитку для ідентифікатора. У цьому випадку forIndexPath:повертається старша (не ) версія nil.

Ви реєструєте клас для ідентифікатора, відправивши registerClass:forCellReuseIdentifier:його у подання таблиці. Ви зареєструєте нитку для ідентифікатора, відправивши registerNib:forCellReuseIdentifier:в подання таблиці.

Якщо ви створюєте подання таблиці та прототипи вашої комірки на дошці розкадрувань, завантажувач розкадрованих верстатів піклується про реєстрацію прототипів комірок, визначених вами в таблиці.

Сесія 200 - Що нового у Cocoa Touch від WWDC 2012 обговорює (тоді вже нова) forIndexPath:версія, починаючи з 8:30. У ньому йдеться про те, що "ви завжди отримаєте ініціалізовану комірку" (не згадуючи, що вона вийде з ладу, якщо ви не зареєстрували клас чи прямування).

У відео також йдеться про те, що "це буде правильний розмір для цього шляху індексу". Імовірно, це означає, що вона встановить розмір комірки перед поверненням, переглянувши власну ширину подання таблиці та зателефонувавши tableView:heightForRowAtIndexPath:методу вашого делегата (якщо визначено). Ось чому йому потрібен шлях до індексу.


Це дуже корисно, дякую. Наявність розміру комірки в час декетування здається меншою перевагою з обмеженнями автоматичного розміру та розмітки?
Бенджон

38

dequeueReusableCellWithIdentifier:forIndexPath:буде завжди повертатися в клітку. Він або повторно використовує наявні комірки, або створює нову та повертається, якщо немає комірок.

Тоді як традиційний dequeueReusableCellWithIdentifier:поверне клітинку, якщо вона існує, тобто якщо є клітина, яку можна повторно використати, вона повертає те, що вона повертає нуль. Таким чином, вам доведеться написати умову, щоб перевірити також nilцінність.

Щоб відповісти на запитання, використовуйте, dequeueReusableCellWithIdentifier:коли ви хочете підтримувати версії iOS 5 та новіших версій, оскільки dequeueReusableCellWithIdentifier:forIndexPathце доступно лише для iOS 6+

Довідка: 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 - повинен зареєструвати nb або клас для ідентифікатора або з'єднати комірку прототипу в
дошці

@binarystar Ви повинні зареєструвати нитку або клас вашої користувальницької комірки з огляду на те, що завантажилися. як:[self.tableView registerNib:[UINib nibWithNibName:@"cell" bundle:nil] forCellReuseIdentifier:@"cell"];
GoodSp33d

6

Я ніколи не розумів, чому Apple створила новіший метод, dequeueReusableCellWithIdentifier: forIndexPath :. Їх документація на них не є повною і дещо вводить в оману. Єдина відмінність, яку я зміг розрізнити між двома методами, полягає в тому, що цей старший метод може повернути нуль, якщо він не знайде клітинку з ідентифікатором, переданим у той час, коли новий метод руйнується, якщо він не може повернутися клітина. Обидва способи гарантують повернення комірки, якщо ви правильно встановили ідентифікатор, і перетворіть клітинку в розкадровку. Обидва способи також гарантовано повернуть клітинку, якщо ви зареєструєте клас або xib і зробите свою комірку в коді або файлі xib.


3
Новий метод використовує шлях індексу для визначення належного розміру для комірки.
грабувати майофф

1
@robmayoff Але це має сенс? Без нового методу розмір комірки все ще можна встановити належним чином. Чи може новий метод запропонувати будь-яку зручність?
fujianjin6471

1
Прочитайте останній абзац моєї відповіді для деталей.
грабувати майофф

Так це означає, що якщо всі мої клітини однакових розмірів у таблиці, не має значення, який метод я викликаю?
Happiehappie

2
Якщо я надаю tableView.estimateHeight, розмір комірки також буде визначений належним чином. Я все одно не отримую переваги від нового методу.
Райан

1

Коротше:

dequeueReusableCell(withIdentifier, for)працює лише з прототипами комірок. Якщо ви спробували використати його, коли комірка-прототип відсутня, це перерве додаток.

Hollemans M. 2016, розділ 2 Контрольний список, учень IOS (5-е видання). с .: 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()
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.