Luke Irvin
Luke Irvin

Reputation: 1249

Images cached are flickering

I'm downloading images from Cloud Storage and they are used throughout my app. I have them cached but I still see some flickering when my tables scroll or are reloaded.

Here's what I have tried:

My cache code:

import UIKit

class ImageService {

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

    static func downloadImage(withURL url:URL, completion: @escaping (_ image:UIImage?)->()) {
        let dataTask = URLSession.shared.dataTask(with: url) { data, responseURL, error in
            var downloadedImage: UIImage?

            downloadedImage = nil

            if let data = data {
                downloadedImage = UIImage(data: data)
            }

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

            DispatchQueue.main.async {
                completion(downloadedImage)
            }
        }

        dataTask.resume()
    }

    static func getImage(withURL url:URL, completion: @escaping (_ image:UIImage?)->()) {
        if let image = cache.object(forKey: url.absoluteString as NSString) {
            print("IMAGE IS LOADED FROM CACHE!!!!")
            DispatchQueue.main.async {
                completion(image)
            }
        } else {
            print("IMAGE IS LOADED FROM DOWNLOAD!!!!")
            downloadImage(withURL: url, completion: completion)
        }
    }
}

And here is an example in one of my tables:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    cell.imageView.image = nil

    let storage = Storage.storage()
    let storageRef = storage.reference()
    let imageRef = storageRef.child(String(format: "images/%@.jpg", id))

    imageRef.downloadURL { (URL, error) in
        if error == nil {
            DispatchQueue.main.async {
                ImageService.getImage(withURL: URL!, completion: { image in
                   cell.imageView.image = image
              })
           }
        } else {
          cell.imageView.image = UIImage (named: "placeholder")
        }
    }
}

I see that when I first load my app the images are downloaded and then after that they load from cache. But I still see them flicker. Any suggestions to update the above to either cache to memory & disk or to fix the flickering issue?

Solution:

I am using FirebaseUI which has a modified version of SDWebImage to cache based on the Storage Reference.

Upvotes: 2

Views: 1616

Answers (2)

Zack Cheang Weng Seong
Zack Cheang Weng Seong

Reputation: 338

TBH I dont know if this will work. But I had the same issue, somewhere you have to set the cell.imageview to nil

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// cell.imageView.image = nil (remove)

let storage = Storage.storage()
let storageRef = storage.reference()
let imageRef = storageRef.child(String(format: "images/%@.jpg", id))

imageRef.downloadURL { (URL, error) in
    if error == nil {
        DispatchQueue.main.async {

            ImageService.getImage(withURL: URL!, completion: { image in
               cell.imageView.image = nil //add
               cell.imageView.image = image
          })
       }
    } else {
      cell.imageView.image = nil // Add
      cell.imageView.image = UIImage (named: "placeholder")
    }
}
}

Upvotes: 1

El Tomato
El Tomato

Reputation: 6707

You should take the following lines out of the UITableView delegate method.

let storage = Storage.storage()
let storageRef = storage.reference()

And make them class variables.

Upvotes: 0

Related Questions