Подтвердить что ты не робот

IOS UITableView: какая разница между "cellForRowAtIndexPath" и "willDisplayCell: forRowAtIndexPath:"

Так же, как в заголовке вопроса: Какая разница между "cellForRowAtIndexPath" и "willDisplayCell: forRowAtIndexPath:"? `

Я думаю, что конфигурация ячейки может быть выполнена либо в cellForRowAtIndexPath, либо willDisplayCell: forRowAtIndexPath: "!

4b9b3361

Ответ 1

Вы правы, конфигурация ячеек может (теоретически) выполняться в обоих методах.

Однако почти все UITableView имеют источник данных, который реализует cellForRowAtIndexPath: (это обязательный метод в протоколе). С другой стороны, willDisplayCell:forRowAtIndexPath: (который является методом делегата, а не источника данных) является необязательным.

Поскольку настройка ячейки обычно зависит от данных, которые вы хотите показать, cellForRowAtIndexPath:, безусловно, является наиболее распространенным местом для настройки соты. (Я даже не могу вспомнить использование willDisplayCell:forRowAtIndexPath:).

Есть одно заметное исключение: когда вы используете раскадровку и статические ячейки (вместо прототипов ячеек), вы не можете делать ничего полезного в cellForRowAtIndexPath: (потому что dequeueReusableCellWithIdentifier: возвращает nil), поэтому вам нужно выполнить настройку в willDisplayCell:forRowAtIndexPath:, viewWillAppear: или других методах.

@NSDeveloper: вы правы. Спасибо за подсказку.

Ответ 2

Я думаю, что это отвечает на ваш вопрос:

Но очень важная вещь все еще существует: tableView:cellForRowAtIndexPath:, который должен быть реализованный в dataSource UITableView, вызываемый для каждой ячейки и должен работать быстро. Таким образом, вы должны вернуть экземпляр повторно использованной ячейки как можно быстрее насколько это возможно.

Dont выполнить привязку данных в этот момент, потому что на экране еще нет ячейки. Для этого вы можете использовать tableView:willDisplayCell:forRowAtIndexPath:, который может быть реализован в делегате UITableView. Метод, называемый точно перед показом ячейки в границах UITableViews.

От идеальной гладкой прокрутки в UITableViews

Ответ 3

cellForRowAtIndexPath должен действительно вернуть экземпляр ячейки. Когда это возможно, это должна быть повторно использованная ячейка. Этот метод необходим для протокола UITableViewDataSource. Обычно вы выбираете данные, которые будут отображаться в ячейке. С динамическими ячейками он обычно задает свойства пользовательского интерфейса, такие как выбранное состояние, в то же время, когда вы устанавливаете данные здесь.

willDisplayCell является необязательным и вызывается после. Это ваш последний шанс настроить ячейку перед ее отображением. На этом этапе экземпляр ячейки уже создан. Здесь вы можете изменить такие вещи, как выбранное состояние и т.д. Вы не должны изменять данные/структуру ячейки или создавать что-то новое, но только изменяете состояние свойств интерфейса для ячейки. Это обычно используется со статическими ячейками.

Ответ 4

У меня возникла проблема с конфигурацией ячеек в willDisplayCell: при использовании autolayout и UITableViewAutomaticDimension. Высота повторных элементов не вычислялась должным образом. Способы печати в NSLog показывают, что willDisplayCell: вызывается после heightForRowAtIndexPath: (тестируется на симуляторе iOS 10.2)

cellForRowAtIndexPath: <NSIndexPath: 0x7c10daa0> {length = 2, path = 1 - 0}
heightForRowAtIndexPath: <NSIndexPath: 0x7c10daa0> {length = 2, path = 1 - 0}
heightForRowAtIndexPath: <NSIndexPath: 0x7c10daa0> {length = 2, path = 1 - 0}
willDisplayCell: <NSIndexPath: 0x7c10daa0> {length = 2, path = 1 - 0}
cellForRowAtIndexPath: <NSIndexPath: 0x7c4516f0> {length = 2, path = 1 - 1}
heightForRowAtIndexPath: <NSIndexPath: 0x7c4516f0> {length = 2, path = 1 - 1}
heightForRowAtIndexPath: <NSIndexPath: 0x7c4516f0> {length = 2, path = 1 - 1}
willDisplayCell: <NSIndexPath: 0x7c4516f0> {length = 2, path = 1 - 1}

Я думаю, что это была причина, потому что проблема пошла после размещения кода конфигурации в cellForRowAtIndexPath:

P.S. Есть ссылка на ссылку и цитату, отправленную @iTSangar: https://tech.zalando.com/blog/proper-use-of-cellforrowatindexpath-and-willdisplaycell/

Ответ 5

Несмотря на то, что может показаться интуитивно понятным, ячейка displayDisplay: называется сразу после вызываемой ячейки cellForRowAt indexPath:

У меня было приложение, в котором изображения и видео загружались из URL-адреса или загружались и отображались в ячейке. Я заметил, что всякий раз, когда я запускаю приложение, все видео и изображения загружаются, прежде чем я смогу их увидеть, и я это заметил, потому что слышал звук из последнего видео в tableView, рассматривая первый элемент в таблицеView. Это 8 элементов в таблицеView. Я напечатал на консоли, чтобы лучше понять, что такое порядок вызовов функций делегата.

Результаты:

  • Создана ячейка в строке 0
    • Поместить ячейку канала в строку 0
  • Создана ячейка в строке 1
    • Ячейка для рисования в строке 1
  • Создана ячейка в строке 2
    • Ячейка для рисования в строке 2
  • Создана ячейка в строке 3
    • Ячейка Drew в строке 3
  • Создана ячейка в строке 4
    • Ячейка для рисования в строке 4
  • Создана ячейка в строке 5
    • Ячейка для рисования в строке 5
  • Создана ячейка в строке 6
    • Ячейка Drew в строке 6
  • Создана ячейка в строке 7
    • Ячейка для рисования в строке 7
  • Остановлен показ ячейки в строке 2
  • Остановлен показ ячейки в строке 3
  • Остановить показ ячейки в строке 4
  • Остановить показ ячейки в строке 5
  • Остановлен показ ячейки в строке 6
  • Остановлен показ ячейки в строке 7

Код:

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "feedCell", for: indexPath) as! FeedCell
    print("Created cell at row \(indexPath.row)")
    let post = posts[indexPath.row]
    cell.post = post
    cell.viewController = self
    cell.configureCell()
    return cell
}

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if let feedCell = cell as? FeedCell{
        print("Drew feed cell at row \(indexPath.row)")
        // only want download task to start when the cell will display
        if feedCell.post.isVideo {
            feedCell.loadVideo()
        } else {
            feedCell.loadImage()
        }
    }
}

override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    print("Stopped showing cell at row \(indexPath.row)")
    if let feedCell = cell as? FeedCell{
        feedCell.player?.pause()
    }
}