Когда использовать dequeueReusableCellWithIdentifier против dequeueReusableCellWithIdentifier: forIndexPath

118

Есть две перегрузки для dequeueReusableCellWithIdentifier, и я пытаюсь определить, когда следует использовать один или другой?

В яблочных документах, касающихся функции forIndexPath, говорится: "Этот метод использует путь индекса для выполнения дополнительной настройки, основанной на позиции ячеек в представлении таблицы".

Я не уверен, как это интерпретировать?

Теги:

5 ответов

165
Лучший ответ

Самое важное отличие состоит в том, что версия forIndexPath: утверждает (сбой), если вы не зарегистрировали класс или ниб для идентификатора. Более старая версия (forIndexPath:) возвращает nil в этом случае.

Вы регистрируете класс для идентификатора, отправив registerClass:forCellReuseIdentifier: в представление таблицы. Вы регистрируете наконечник для идентификатора, отправив registerNib:forCellReuseIdentifier: в представление таблицы.

Если вы создаете представление в виде таблицы и прототипы соты в раскадровке, загрузчик раскадровки позаботится о регистрации прототипов соты, которые вы определили в раскадровке.

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

В видео также говорится, что "это будет правильный размер для этого указательного пути". Предположительно это означает, что он установит размер ячейки перед ее возвратом, просмотрев собственную ширину таблицы и вызов метод делегата tableView:heightForRowAtIndexPath: (если он определен). Вот почему ему нужен указательный путь.

  • 0
    Это действительно полезно, спасибо. Размер ячейки во время ожидания кажется меньшим преимуществом с автоматическими размерами и ограничениями макета?
26

dequeueReusableCellWithIdentifier:forIndexPath: будет всегда возвращать ячейку. Он либо повторно использует существующие ячейки, либо создает новый, и возвращает, если нет ячеек.

В то время как традиционный dequeueReusableCellWithIdentifier: вернет ячейку, если она существует. Если есть ячейка, которую можно повторно использовать, она возвращает это, иначе она возвращает nil. Таким образом, вам нужно будет написать условие для проверки значения 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:

  • 0
    Нет, он не всегда возвращает ячейку 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 - необходимо зарегистрировать ниб» или класс для идентификатора или подключите ячейку прототипа в раскадровке
  • 0
    @binarystar Вы должны зарегистрировать перо или класс вашей пользовательской ячейки, поскольку он загружен. например: [self.tableView registerNib:[UINib nibWithNibName:@"cell" bundle:nil] forCellReuseIdentifier:@"cell"];
5

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

  • 2
    Новый метод использует путь индекса для определения правильного размера ячейки.
  • 0
    @robmayoff Но имеет ли это какой-то смысл? Без нового метода размер ячейки все еще может быть установлен правильно. Может ли новый метод предложить какое-либо удобство?
Показать ещё 3 комментария
0

Короче:

dequeueReusableCell(withIdentifier, for) работает только с прототипом клетки. Если вы попытаетесь использовать его, когда ячейка прототипа отсутствует, это приведет к сбою приложения.

Hollemans M. 2016, глава 2 Контрольный список, IOS Apprentice (5-е издание). pp. 156.

0

Я бы рекомендовал использовать оба варианта, если вы используете динамически сгенерированный контент. В противном случае приложение может неожиданно аварийно завершить работу. Вы можете реализовать свою собственную функцию для извлечения дополнительной ячейки многократного использования. Если это nil, вы должны вернуть пустую ячейку, которая не видна:

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

И расширение для возврата пустой ячейки:

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню