У меня есть UICollectionView, чьи ячейки совершают вызовы данных в cellForItemAt
:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellReuseIdentifier, for: indexPath) as? CustomCell
else { return UICollectionViewCell() }
cell.viewModel = viewModel.viewModelForCell(at: indexPath.row)
cell.populate() // this causes the cell's ViewModel to fetch a thumbnail image
return cell
}
Метод populate()
заставляет ViewModel ячейки извлечь изображение, чтобы ячейка отображалась в виде эскиза.
Ячейки также могут отменить выборку для этих миниатюр. Например, если пользователь прокручивает ячейку до загрузки ее миниатюры, я отменяю сетевой вызов, начатый в cellForItem
. Эта отмена в настоящее время происходит в didEndDisplaying
:
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let cellViewModel = viewModel.viewModelForCell(at: indexPath.row)
cellViewModel.cancelThumbnailFetch()
}
Это вызывает проблему в следующей ситуации: ячейка, которая активно извлекает изображение, прокручивается за пределы экрана (запускает didEndDisplaying
, который отменяет извлечение), затем пользователь прокручивает обратно к ячейке, а затем прокручивает ее достаточно далеко для повторного использования ячейки (что вызвало бы повторный вызов cellForItem
для повторного запуска выборки). В этом сценарии выборка никогда не начинается.
Я могу это исправить, позвонив populate()
в willDisplayCell
:
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
guard let cell = cell as? CustomCell else {
return
}
cell.populate()
}
Но дважды вызывая populate()
, как это каждый раз, когда появляется ячейка (один раз в cellForItem
и опять в willDisplayCell
) кажется очень неаккуратным. Я всегда могу просто удалить вызов populate()
в cellForItem
, но тогда я теряю преимущество запуска извлечения как можно скорее. Для справки: миниатюры и их задачи с данными все кэшируются локально, поэтому двойной вызов populate()
не вызывает проблем с производительностью (т. Е. Не будет нескольких задач с данными, работающих при загрузке одного и того же эскиза); Меня больше беспокоит чистота кода всего этого