Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AFNetworking Image cache does not empty on memory warning

I have an image heavy application where i download images using the UIImageView+AFNetworking category.

I noticed that my memory footprint would continue to rise as i loaded more and more images. When i eventually got a memory notification it did not release any memory - and thus the application crashed. My Understanding of This is that AFNetworking uses a subclass of NSCache called AFImageCache which should handle memory warnings on it's own. Link 1 Link 2

With some dirty hacks, I manually cleared all the objects from the shared cache, and saw a significant decrease in memory allocations. This never seem to happen without manually doing this call.

Allocation instruments

I have duplicated this in a simple application which downloads the front page of Imgur and displays it in a simple tableview. Above you can see the allocation profiling done for the applpication.

I have tried to remove anything fancy and the code is messy at some places. It does not include my dirty-hack, so it simply dies at memory warnings. You can see the application here.

You need to setup an application at imgur to use it.

Reading through github issues Mattt seem to indicate that it should be enough and fully self maintaining, as long as you set proper cache policy to the NSURLRequest you pass in. I might be missing something, but I'm not certain what cache policy I would set. It all seem to regard refetching changed images rather than clearing for the sake of memory.

I also think lieven is touching on the same problem in this issue saying that unless the totalCostLimit is set the cache won't self clean. Although I don't trust using the simulator paired with simulated memory warnings in cases like these, the symptoms are the same.

I appreciate any help debugging this

Edit

Profiling update after adding the suggested code from

enter image description here

like image 748
niklasdstrom Avatar asked Feb 04 '14 00:02

niklasdstrom


1 Answers

AFNetworking's image cache uses NSCache, which clears on system-wide memory pressure, but not an individual app's memory warning.

To address this, the 2.x branch of AFNetworking added this code:

[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * __unused notification) {
    [_af_defaultImageCache removeAllObjects];
}];

which will clear the cache on a memory warning.

If you're still on the 1.x branch, this code is not included (UPDATE: it has been added in this commit) which can result in the behavior you see. You could update to 2.x, or just add this code into your app.

it should be enough and fully self maintaining, as long as you set proper cache policy to the NSURLRequest you pass in

Note that NSCache and NSURLCache are two very different classes. NSCache is the one you're looking for in your question. NSURLCache, on the other hand, only caches responses to URL load requests.

UIImageView+AFNetworking uses NSCache to store UIImage objects. NSURLCache stores NSData objects, and retrieving objects from this cache is typically not performant enough for image-heavy applications that show images in a UITableView or UICollectionView.

Finally, you may want to compare your implementation with one that uses the SDWebImage project. SDWebImage offers disk and memory caching, and gives you much more control over the details than AFNetworking's UIImageView+AFNetworking.

like image 148
Aaron Brager Avatar answered Oct 22 '22 10:10

Aaron Brager