Что я делаю неправильно при кэшировании изображений для ячеек UITableView - PullRequest
0 голосов
/ 10 июня 2019

В основном я создаю приложение, которое будет использовать данные из остальных API. В его данных также есть пара изображений, которые пришли в качестве URL для загрузки. Таким образом, я думаю, что было бы лучше загрузить эти изображения только один раз, затем я кеширую их для повторного использования в моих ячейках UITableView и так далее. Что я должен сделать, чтобы правильно использовать эту функцию?

Итак, начнем. Сначала я создал следующий класс для обработки изображений загрузки / кэширования:

class ImageService {

    static let cache = NSCache<NSString, UIImage>()

    static func downloadImage(url:URL, completion: @escaping (_ image:UIImage?)->()) {

        let dataTask = URLSession.shared.dataTask(with: url) { (data, response, error) in
            var downloadedImage:UIImage?

            if let data = data {

                downloadedImage = UIImage(data: data)
            }

            if downloadedImage != nil {
                self.cache.setObject(downloadedImage!, forKey: url.absoluteString as NSString)
            }

            DispatchQueue.main.async {
                completion(downloadedImage)
            }

        }
        dataTask.resume()

    }

    static func getImage(url:URL, completion:@escaping (_ image:UIImage?)->()) {

        if let image = self.cache.object(forKey: url.absoluteString as NSString) {
            completion(image)
        } else {
            downloadImage(url: url, completion: completion)
        }

    }

}

Столкнувшись с кодом выше, в моем классе UITableView, который я только что назвал:

class TableViewController: UITableViewController {

    private var articlesViewModel:ArticleViewModel?


    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.showsVerticalScrollIndicator = false
        self.navigationController?.navigationBar.prefersLargeTitles = true

        //Call Network
        Networking.getApiData(url: Networking.urlRequest) { [weak self] (articles) in

            //Data from API
            self?.articlesViewModel = ArticleViewModel(modelRef: articles)

            DispatchQueue.main.async {
                self?.tableView.reloadData()
            }
        }
    }


    //MARK: TableView DataSource
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1 //Static
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.articlesViewModel?.updateTableCount() ?? 1
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCell.cellIdentifier, for: indexPath) as! TableViewCell

        if let title = self.articlesViewModel?.updateTableTitleForIndex(indexpath: indexPath.row) {
            cell.titleCell.text = title
        }
        if let description = self.articlesViewModel?.updateTableDescriptionForIndex(indexpath: indexPath.row) {
            cell.descriptionCell.text = description
        }
        if let pictureURL = self.articlesViewModel?.updateTableImageForIndex(indexpath: indexPath.row) {
            ImageService.getImage(url: URL(string: pictureURL)!) { (finalImage) in
                cell.imageCell.image = finalImage
            }
        }


        return cell
    }



}

Однако после запуска приложения я получил следующий результат: Похоже, что все кэшированные изображения пришли до того, как я получил результат от API на ViewDidLoad

enter image description here

Если я прокручиваю вниз и снова вверх, я получаю следующий результат: Кажется, все как-то «переупорядочено», тогда все выглядит хорошо.

enter image description here

Дополнительные классы:

ViewModel:

class ArticleViewModel {

    static var articlesRef:[Article]!

    init(modelRef:[Article]) {
        ArticleViewModel.articlesRef = modelRef
    }


    //MARK: Functions
     func updateTableCount() -> Int {
        return ArticleViewModel.self.articlesRef.count
    }

     func updateTableTitleForIndex(indexpath:Int) -> String {
        return ArticleViewModel.self.articlesRef[indexpath].title ?? ""
    }

    func updateTableDescriptionForIndex(indexpath:Int) -> String {
        return ArticleViewModel.self.articlesRef[indexpath].description ?? ""
    }

    func updateTableImageForIndex(indexpath:Int) -> String {
        return ArticleViewModel.self.articlesRef[indexpath].urlToImage ?? ""
    }

}

Сетевой уровень:

class Networking {

    static var urlRequest = "https://newsapi.org/v2/everything?q=apple&from=2019-06-05&to=2019-06-05&sortBy=popularity&apiKey=04d5f33acdde48f1a22a90f46fc483b5"


    static func getApiData(url: String?, _ completion:@escaping([Article]) -> ()) {

        guard let unrwpUrl = url else {return}

        let request = URL(string: unrwpUrl)

        URLSession.shared.dataTask(with: request!) { (data, request, error) in

            if let data = data {

                do {
                    let decodedData = try JSONDecoder().decode(Articles.self, from: data)


                    completion(decodedData.articles)

                }catch{
                    print(error.localizedDescription)
                }
            }


            }.resume()
    }
}

Модель:

struct Articles: Decodable {
    let articles:[Article]
}

struct Article: Decodable {
    let title:String?
    let author:String?
    let description:String?
    let urlToImage:String?
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...