Как отключить загрузку изображений ячейки TableView, когда они появляются - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть TableView с ImageViews внутри каждой ячейки. Я хочу, чтобы изображения загружались один раз и оставались такими, но кажется, что изображения загружаются (загружаются, я получаю их из внешнего API), когда они попадают в видимую область для пользователя. Это похоже на ленивую загрузку или что-то в этом роде, и я хотел бы отключить ее, потому что если я прокручиваю вниз, то возвращаюсь вверх, большинство изображений теряется.

TableViewController.swift

cell?.mainChampImageView.image = businessLayer.getChampionThumbnailImage(championId: mainChampion.key)

BusinessLayer.swift

func getChampionThumbnailImage (championId: Int) -> UIImage {
        return dataLayerRiot.getChampionThumbnailImage(championId: championId)
    }

DataLayerRiot.swift

func getChampionThumbnailImage (championId: Int) -> UIImage {
        var image: UIImage!

        let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
        let url = URL(string: urlString)
        let session = URLSession.shared

        let semaphore = DispatchSemaphore(value: 0)

        session.dataTask(with: url!) {(data, response, error) in
            if error != nil {
                print("ERROR")
                semaphore.signal()
            }
            else {
                image = UIImage(data: data!)!
                semaphore.signal()
            }
        }.resume()

        semaphore.wait()
        session.finishTasksAndInvalidate()

        return image
    }

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

EDIT

Я снимаю очередь с ячейки по умолчанию

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "Match", for: indexPath) as? TableViewCell
        ...
}

Есть ли лучший способ сделать это?

РЕДАКТИРОВАТЬ 2

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

Ответы [ 3 ]

0 голосов
/ 09 ноября 2018

Попробуйте SDWebImage для отложенной загрузки изображений в UITableViewCell или UICollectionViewCell. Установите его через cocoapods в ваш проект.

Это кэширование асинхронной памяти + образа диска с автоматической обработкой срока действия кэша.

https://github.com/SDWebImage/SDWebImage

Код:

let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
let url = URL(string: urlString)
cell?.mainChampImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "placeholder.png"))
0 голосов
/ 10 ноября 2018

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

Я создал класс с именем ImageCache, и в данном случае он является одноэлементным, поэтому кэш доступен во всем приложении.

import UIKit

class ImageCache: NSObject {
    static let sharedImageCache = ImageCache()

    // Initialize cache, specifying that your key type is AnyObject
    // and your value type is AnyObject. This is because NSCache requires 
    // class types, not value types so we can't use <URL, UIImage>

    let imageCache = NSCache<AnyObject, AnyObject>()

    // Here we store the image, with the url as the key
    func add(image: UIImage, for url: URL) {
        // we cast url as AnyObject because URL is not a class type, it's a value type
        imageCache.setObject(image, forKey: url as AnyObject)
    }


    // This allows us to access the image from cache with the URL as the key
    // (e.g. cache[URL])
    func fetchImage(for url: URL) -> UIImage? {
        var image: UIImage?

        // Casting url for the same reason as before, but we also want the result
        // as an image, so we cast that as well
        image = imageCache.object(forKey: url as AnyObject) as? UIImage
        return image
    }
}

Так что теперь у нас есть относительно простое кеширование. Теперь о том, как его использовать:

func getChampionThumbnailImage (championId: Int) -> UIImage {
    var image: UIImage!

    let urlString = ApiHelper.getChampionThumbnailImageApiLink(championId: championId)
    let url = URL(string: urlString)

    // Before, downloading the image, we check the cache to see if it exists and is stored.
    // If so, we can grab that image from the cache and avoid downloading it again.
    if let cachedImage = ImageCache.sharedImageCache.fetchImage(for: url) {
        image = cachedImage
        return image
    }

    let session = URLSession.shared

    let semaphore = DispatchSemaphore(value: 0)

    session.dataTask(with: url!) {(data, response, error) in
        if error != nil {
            print("ERROR")
            semaphore.signal()
        }
        else {
            image = UIImage(data: data!)!
            // Once the image is successfully downloaded the first time, add it to 
            // the cache for later retrieval
            ImageCache.sharedImageCache.add(image: image, for: url!)
            semaphore.signal()
        }
    }.resume()

    semaphore.wait()
    session.finishTasksAndInvalidate()

    return image
}

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

Вы можете избежать повторной загрузки изображений, внедрив кэширование.

Еще один способ избежать неправильных изображений - установить нулевое представление изображения перед повторной загрузкой изображения. Например:

cell?.mainChampImageView = nil
cell?.mainChampImageView.image = businessLayer.getChampionThumbnailImage(championId: mainChampion.key)

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

0 голосов
/ 09 ноября 2018

Вы должны сохранить задачу в памяти как:

let task = = session.dataTask() {}

И после того, как вы можете отменить его в любом месте:

task.cancel()

В качестве альтернативы, если сеанс объекта является экземпляром URLSession, вы можете отменить его:

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