UICollectionView повторного использования ячеек и онлайн-изображений - PullRequest
0 голосов
/ 21 сентября 2018

Я пытаюсь понять, как работает повторное использование ячеек UICollectionView.

В настоящее время я реализую UICollectionView с горизонтальной прокруткой и большими ячейками, которые занимают почти весь размер экрана.Имеется около 100+ ячеек, но вы когда-нибудь увидите только ~ 3.

Как я понимаю, повторное использование ячеек UICollectionView просто поддерживает пул инициализированных объектов ячеек таким образом, когда одна ячейка не видна, она можетбыть каннибализированным недавно видимой ячейкой.То есть, поскольку я использую повторное использование, коллекция может инициализировать только ~ 3 фактических объекта ячейки в памяти, и я просто переключу их содержимое.

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

Если действительно есть пул моих пользовательских объектов ячейки, это означает, что этого совершенно не происходит.,Каждый раз, когда появляется ячейка, я начинаю совершенно новую загрузку.

Как я должен делать это правильно?

Основная причина, по которой я спрашиваю это, заключается в том, что при прокрутке (особеннона начальной прокрутке) Я вижу некоторое мерцание между изображением старой ячейки и изображением, которое ячейка должна отображать.Я сделал исправление, но я вполне уверен, что это приводит к тому, что онлайн-изображения загружаются слишком частоЯ делаю это правильно?

public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as? ImageCell else {
        assert(false)
    }
    let image = data[indexPath.row]
    cell.display(title: image.title, imageURL: image.imageURL)
    return cell
}

И клетка

public class NewsCell: UICollectionViewCell {
    private var title: UILabel = UILabel()
    private var imageView: UIImageView = UIImageView()

    override public init(frame: CGRect = CGRect.zero) {
        super.init(frame: frame)

        title.font = UIFont.systemFont(ofSize: 12, weight: .bold)
        title.textColor = UIColor.white
        title.textAlignment = NSTextAlignment.left

        imageView.contentMode = UIViewContentMode.scaleAspectFill
        imageView.clipsToBounds = true

        contentView.addSubview(imageView)
        imageView.addSubview(title)

    // Layout constraints
    }

    public func display(title: String, imageURL: URL?) {
        self.imageView.image = nil
        self.title.text = title
        if let url = imageURL {
            downloadImage(from: url)
        }
    }

    func downloadImage(from url: URL) {
        getData(from: url) { data, response, error in
            guard let data = data, error == nil else {
                return
            }
            DispatchQueue.main.async {
                self.imageView.image = UIImage(data: data)
            }
        }
    }

    func getData(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> Void) {
        URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
    }

}

Меня беспокоит тот факт, что я должен установить для изображений представления изображения ноль на дисплее, чтобы предотвратитьМерцаниеДолжен ли я делать что-то по-другому, чтобы избежать легкомысленной загрузки этих изображений, или это выглядит хорошо?

1 Ответ

0 голосов
/ 22 сентября 2018
  1. Вы можете использовать Предварительная выборка Просмотр данных коллекции , чтобы загрузить изображения раньше.

Вы используете предварительную выборку данных, когда загрузка данных является медленным или дорогим процессом- например, при получении данных по сети.В этих условиях выполнять загрузку данных асинхронно.

Это потребует некоторых изменений, конечно.Вам нужно будет хранить свои изображения отдельно и загружать их, когда будет вызван метод DataSourcePrefetching.Кроме того, затем изображение загружается, вам нужно проверить, есть ли ячейка, которая ожидает этого изображения.Так что ваш UICollectionView больше ничего не загрузит.Он покажет только изображение или ожидает его загрузки.

Проблема с вашим текущим решением.Если вы будете прокручивать слишком быстро, вы столкнетесь с ситуацией, когда из-за повторного использования тот же UICollectionViewCell загружает несколько изображений одновременно.И в этом случае пользователь увидит только последний, и вы никогда не сможете сказать, какой это будет.Чтобы избежать этого состояния гонки, вы можете сохранить идентификатор изображения или его URL в ячейке, чтобы после завершения загрузки можно было проверить, является ли загруженное изображение правильным.

Можно установить image на ноль во время загрузки, но вы также можете показать пользователю UIActivityIndicatorView, чтобы он мог видеть, что какая-то работа происходит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...