Как правильно использовать prepareForReuse?
Нужна помощь с пониманием того, как использовать prepareForReuse() в UIKit. В документации сказано
Вам следует сбрасывать только те атрибуты ячейки, которые не связаны с содержимым, например, альфа, редактирование и состояние выбора.
а как насчет сброса отдельных атрибутов свойств, таких как isHidden?
Предполагая, что моя ячейка имеет 2 метки, куда я должен сбросить:
- label.text
- label.numberOfLines
- label.isHidden
Мой делегат tableView(_:cellForRowAt:) имеет условную логику для скрытия / отображения меток для каждой ячейки.
3 ответа
Не использовать prepareForReuse
совсем. Он существует, но очень мало ситуаций, когда он полезен, а ваша - не одна из них. Делать всю работу в tableView(_:cellForRowAt:)
,
Цитирование из собственной документации Apple:
Из соображений производительности следует сбрасывать только те атрибуты ячейки, которые не связаны с содержимым, например альфа, редактирование и состояние выбора.
например, если ячейка была выбрана, вы просто устанавливаете ее как невыбранную, если вы изменили цвет фона на что-то, то вы просто сбросили его на цвет по умолчанию.
Делегат табличного представления в
tableView(_:cellForRowAt:)
должен всегда сбрасывать все содержимое при повторном использовании ячейки.
Это означает, что если вы пытаетесь установить изображения профиля в вашем списке контактов, вы не должны пытаться nil
изображения в prepareforreuse
, вы должны правильно установить ваши изображения в cellForRowAt
и если вы не нашли ни одного изображения, вы устанавливаете его на nil
или изображение по умолчанию. В основном cellForRowAt
должен регулировать как ожидаемый / неожиданный статус.
Таким образом, в основном следующее не предлагается:
override func prepareForReuse() {
super.prepareForReuse()
imageView?.image = nil
}
вместо этого рекомендуется следующее:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
cell.imageView?.image = image ?? defaultImage // unexpected situation is also handled.
// We could also avoid coalescing the `nil` and just let it stay `nil`
cell.label = yourText
cell.numberOfLines = yourDesiredNumberOfLines
return cell
}
Дополнительно рекомендуется использовать элементы, не относящиеся к содержанию по умолчанию, как показано ниже:
override func prepareForReuse() {
super.prepareForReuse()
isHidden = false
isSelected = false
isHighlighted = false
}
Это предложенный Apple способ. Но, если честно, я все еще думаю, что легче все бросить внутри cellForRowAt
как сказал Мэтт. Чистый код важен, но на самом деле это не поможет вам достичь этого. Но, как сказал Коннор, единственное время, когда это необходимо, это если вам нужно отменить загружаемое изображение. Подробнее смотрите здесь
т.е. сделать что-то вроде:
override func prepareForReuse() {
super.prepareForReuse()
imageView.cancelImageRequest() // this should send a message to your download handler and have it cancelled.
imageView.image = nil
}
Как указано в документации, вы должны использовать указанный метод только для сброса атрибутов, не связанных с контентом. Что касается сброса текста / количества строк.... ваших меток, вы можете сделать это из tableView(_:cellForRowAt:) непосредственно перед тем, как установить новое значение, например:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell.label.text = "" //reseting the text
cell.label.text = "New value"
return cell
}
ИЛИ ЖЕ
Вы могли бы использовать более объектно-ориентированный подход и создать подкласс UITableViewCell и определить метод, скажем configureCell(), чтобы иметь дело со всеми настройками сброса и значения для вновь удаленных ячеек.