Как сделать этот код асинхронным на Swift - PullRequest
1 голос
/ 08 марта 2020

У меня есть массив строк, содержащий URL-адреса фотографий. У меня есть пользовательский макет, и мне нужно преобразовать массив строк в UIImage, а затем получить их размер. Вот мой код:

extension PhotoFeedViewController: CustomLayoutDelegate {

func collectionView(_ collectionView: UICollectionView, sizeOfPhotoAtIndexPath indexPath: IndexPath) -> CGSize {

    let bodyImage = UIImageView()
    let url = URL(string: collectionPhotos[indexPath.row])

    let data = try? Data(contentsOf: url!)
//        DispatchQueue.main.async {
        if let imageData = data {
            bodyImage.image = UIImage(data: imageData)
        }
//        }

    return bodyImage.image?.size ?? CGSize(width: 100, height: 100)
   }
}

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

Если вы раскомментируете:

DispatchQueue.main.async {

Возвращенное свойство пустое и не видит код, который находится в блоке отправки

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

Извините за мой Engli sh.

1 Ответ

1 голос
/ 08 марта 2020

Вы абсолютно правы, что синхронные запросы являются проблемой. (И мы часто используем URLSession, а не просто заключаем его в async вызов.)

Но вам, возможно, придется фундаментально переосмыслить этот процесс. Вы действительно не хотите загружать изображение, чтобы определить его размер, просто чтобы повторно загрузить его снова в cellForItemAt. (И я бы не советовал полагаться на URLCache, чтобы спасти вас.)

В идеале, если источник этого массива URL-адресов мог бы одновременно вернуть размер изображений и отрезал бы Гордиан морской узел. Если бы у вас был список URL-адресов и соответствующие размеры изображений, это позволило бы устранить все проблемы, обсуждаемые ниже.

Если этого не сделать, вы можете воспользоваться двумя основными альтернативами:

  1. Хотите ли вы просто принудительно заставить все изображения иметь одинаковый размер в пользовательском интерфейсе независимо от размера фактического изображения (например, и использовать режим содержимого «заполнение аспектного масштаба»)? Это было бы проще всего.

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

В последнем подходе много осложнения:

  • Создать менеджер загрузок, который отслеживает загруженные изображения, кэшируя предыдущие загрузки (в идеале, как в памяти, так и в постоянном хранилище). Используя кеш, если вы прокручиваете ячейку в поле зрения, она проверяет, загрузили ли вы уже изображение, и если да, то используйте его. Например, когда вы прокручиваете назад в представлении коллекции, вы не хотите инициировать сетевые запросы для изображений, которые были ранее загружены.

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

  • Таким образом, процедура «размер для этой ячейки» фактически скажет: «Я загрузил изображение? если это так, верните его размер; если не инициировать асинхронную загрузку (которая перезагрузит ячейку после ее завершения) и вернуть некоторый размер заполнителя ». Там будет аналогичный лог c в cellForItemAt.

Несколько других соображений:

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

  • Если вы этого еще не сделали, при решении вышеуказанных проблем может потребоваться предварительная выборка. Это приведет к уменьшению размера сотен ячеек sh, если к моменту прокрутки к определенному смещению содержимого в представлении коллекции изображение уже загружено.

...