Nscache Doesn't Work with All Images When Loading for the First Time

NSCache Doesn't work with all images when loading for the first time

Here the images are downloading and stored in cache just fine. The problem lies in the updation of tableview cells.

When the table view is loading the cells on to the table the images are not downloaded yet. But once the image is downloaded we have to selectively update the cell so that the image is displayed instantly.

Since you are scrolling , the tableview calls 'cellForRowatIndexpath' again which updates the cell showing the downloaded images while scrolling.

If you still wish to use the extension , I suggest you add the tableView and indexpath as the parameters so that we can call reload specific row and have the view updated instantly.

I have updated the table reload code and structure of the function defined in extension. Let me know how it goes.

let imageCache = NSCache<AnyObject, AnyObject>()
var imageURLString : String?

extension UIImageView {


public func imageFromServerURL(urlString: String, tableView : UITableView, indexpath : IndexPath)) {
imageURLString = urlString

if let url = URL(string: urlString) {

image = nil


if let imageFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage {

self.image = imageFromCache

return
}

URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in

if error != nil{
print(error as Any)


return
}

DispatchQueue.main.async(execute: {

if let imgaeToCache = UIImage(data: data!){

if imageURLString == urlString {
self.image = imgaeToCache
}

imageCache.setObject(imgaeToCache, forKey: urlString as AnyObject)// calls when scrolling

tableView.reloadRows(at: [indexpath], with: .automatic)

}
})
}) .resume()
}
}

Does NSCache gets automatically emptied when the app is force quitted?

Yes it does that, for some reason it instantly removes data from cache when app enters background even if there is no memory pressure. To fix this you have to tell NSCache that your data should not be discarded.

What you could do is something like:

class ImageCache: NSObject , NSDiscardableContent {

public var image: UIImage!

func beginContentAccess() -> Bool {
return true
}

func endContentAccess() {

}

func discardContentIfPossible() {

}

func isContentDiscarded() -> Bool {
return false
}
}

and then use this class in NSCache like the following:

let cache = NSCache<NSString, ImageCache>()

After that you have to set the data which you cached earlier:

let cacheImage = ImageCache()
cacheImage.image = imageDownloaded
self.cache.setObject(cacheImage, forKey: "yourCustomKey" as NSString)

And finally retrieve the data:

if let cachedVersion = cache.object(forKey: "yourCustomKey") {
youImageView.image = cachedVersion.image
}

UPDATE

This was already answered by Sharjeel Ahmad. See this link for reference.

NSCache does not work

Every time the method buscarEnCache: is called an new cache object is created with the line:

[[cache alloc] init];

Thus the old cache just leaked and is not available any more.

place the cache = [[NSCache alloc] init]; in the init method of the class.


There is no need to check for the countLimit.

-(UIImage *)buscarEnCache:(UsersController *)auxiliarStruct{
UIImage *image = [cache objectForKey:auxiliarStruct.thumb];

if (!image) {
NSString *imageURLString = [NSString stringWithFormat:@"http://mydomain.com/%@",auxiliarStruct.thumb];
NSURL *imageURL = [NSURL URLWithString:imageURLString];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
image = [UIImage imageWithData:imageData];
[cache setObject:image forKey:auxiliarStruct.thumb];
}

return image;
}

You might want to place the fetch of the image in a method that runs in an other thread and return some kind of placeholder image.

Calling NSCashe doesn't work

you are initializing jsonArray1, just before setting it up.

 jsonArray1 = [Cache objectForKey:@"indexPath"]; // here jsonArray1 = nil; hence remove this line and run your code again. Yo

[Cache setObject:jsonArray1 forKey:@"indexPath"]; // hence you are setting nil value to this key "indexpath"

In that tutorial they are saying like

  • To set a value use following line:

[Cache setObject:jsonArray1 forKey:@"indexPath"];

  • To retrieve a value use following line. This line should be used when you want to used that cached value

jsonArray1 = [Cache objectForKey:@"indexPath"];

In your case, just comment

jsonArray1 = [Cache objectForKey:@"indexPath"];

line and run again. It will not give that error.



Related Topics



Leave a reply



Submit