Reputation: 1249
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
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
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