Как загрузить изображение асинхронно с Swift, используя UIImageViewExtension и предотвращая дублирование изображений или неправильные изображения, загруженные в ячейки - PullRequest
1 голос
/ 12 мая 2019

Я занимаюсь разработкой библиотеки загрузки изображений в Swift 4, например, Kingfisher с некоторыми расширениями для поддержки загрузки изображений из URL в UIImageView.

Так что тогда я могу использовать это расширение на UICollectionили ячейка UITableview с UIImageView следующим образом:

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: 
  "collectioncell", for: indexPath)

    if let normal = cell as? CollectionViewCell {
    normal.imagview.loadImage(fromURL:imageURLstrings[indexPath.row])
  }

По сути, это мой код расширения, реализующий базовый URLSession dataTask и Caching

public extension UIImageView {
public func loadImage(fromURL url: String) {
    guard let imageURL = URL(string: url) else {
        return
    }

    let cache =  URLCache.shared
    let request = URLRequest(url: imageURL)
    DispatchQueue.global(qos: .userInitiated).async {
        if let data = cache.cachedResponse(for: request)?.data, let 
           image = UIImage(data: data) {
             DispatchQueue.main.async {
                self.image = image
            }
        } else {
            URLSession.shared.dataTask(with: request, 
       completionHandler: { (data, response, error) in

            print(response.debugDescription)
                print(data?.base64EncodedData() as Any)
                print(error.debugDescription)
                if let data = data, let response = response, ((response as? HTTPURLResponse)?.statusCode ?? 500) < 300, let image = UIImage(data: data) {
                    let cachedData = CachedURLResponse(response: response, data: data)
                    cache.storeCachedResponse(cachedData, for: request)
                    DispatchQueue.main.async {
                       self.image = image
                    }
                }
            }).resume()
        }
    }
}



 }

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

Это мои результаты

Это зимородки

Как мне запретить моему расширению загружать неправильное изображение в ячейку или дублировать изображения?

1 Ответ

1 голос
/ 12 мая 2019

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

Когда вы запускаете новый запрос на просмотр изображения, предполагая, что вы не нашли изображение в кэше сразу, перед началом сетевого запроса вы должны (а) удалить любое предыдущее изображение (как предложил Брэндон); (б) возможно загрузить изображение заполнителя или UIActivityIndicatorView; и (c) отменить любой предыдущий запрос изображения для этого просмотра изображения. Только тогда вы должны начать новый запрос.

С точки зрения того, как вы сохраняете ссылку на предыдущий запрос в расширении, вы не можете добавить сохраненные свойства, но вы можете использовать objc_setAssociatedObject, чтобы сохранить задачу сеанса при запуске сеанса. установите его равным nil, когда запрос завершится, и objc_getAssociatedObject при получении объекта сеанса, чтобы увидеть, нужно ли отменить предыдущий.

(Кстати, Kingfisher оборачивает эту логику связанного объекта в вычисляемое свойство для идентификатора задачи . Это прекрасный способ сохранить и получить этот идентификатор задачи.


С точки зрения неудачных запросов, тот факт, что вы выполняете необузданные запросы изображений, может вызвать эту проблему. Прокрутите немного, и ваши запросы будут засорены и время ожидания. Выполнение отмены (см. Выше) уменьшит эту проблему, но это все еще может произойти. Если вы по-прежнему не выполняете запросы после исправления вышеизложенного, вам может потребоваться ограничить количество одновременных запросов. Распространенным решением является упаковка запросов в асинхронный подкласс Operation и добавление их в OperationQueue с помощью maxConcurrentOperationCount. Или, если вы ищете дешевое и полезное решение, вы можете попытаться увеличить порог тайм-аута в своих запросах.

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