Segev
Segev

Reputation: 19303

Downloading images using AFNetworking - Memory won't release after poping ViewController using ARC

I've experienced some weird memory issues with my app. After some debugging I've isolated the problem to a new project with one View controller. So right now my testing app contains a UINavigationController connected to a ViewController with a button that pushes the next ViewController:

#import "ViewController.h"
#import "AFNetworking.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    for(int i=0;i<100;i++)
    {
        NSString *rightImageUrl = [NSString stringWithFormat:@"%@/%@-iphone%@.png",ImagesURL,[NSString stringWithFormat:@"%d",i],@"4"];
        UIImageView *rightImageView = [[UIImageView alloc]initWithFrame:CGRectMake(6, 50*i , 139, 200)];
    [rightImageView setImageWithURL:[NSURL URLWithString:rightImageUrl]];
        [self.view addSubview:rightImageView];
    }    
}

The above is all the code I have in my testing app right now.

According to Instruments the above takes X amount of memory (10mb, 20mb .. Depending on the amount of loops) The problem is that the memory allocated from the above won't be released when I'll pop the ViewController.

I've tried wrapping the code inside the for loop with @autoreleasepool but that didn't do much.

Please advise

Upvotes: 1

Views: 866

Answers (1)

Rob
Rob

Reputation: 438417

The UIImageView+AFNetworking category does caching of images using a NSCache subclass, meaning that it will save you from needing to re-retrieve the image (which is incredibly useful, avoiding performance/network impact if you return to this view controller). This cache is automatically purged under memory pressure, so you probably don't need to worry about it (as long as you're confident that your view controller, itself, is getting properly deallocated and doesn't suffer from some strong reference cycle or the like).

If you really want to purge this cache, you'd have to make some changes to the UIImageView+AFNetworking code to expose the AFImageCache class. You'd probably want to make it a proper singleton class (because the existing implementation depends upon UIImageView+AFNetworking to control the af_sharedImageCache) and then you could purge the cache using the NSCache method removeAllObjects.

You probably have to weigh the pros and cons of going through that effort. For example, is it really a problem that it has a cache (because that cache is automatically purged upon memory pressure, anyway)? And if you empty the cache unnecessarily, your app will not enjoy the performance benefits of the cache. If you fork AFNetworking and the author doesn't merge that back into the main branch of the code, then where does that leave you for future AFNetworking updates?

If you decide you want to control the cache, you might also consider excluding AFNetworking+UIImageView from your project and consider using a different UIImageView category that offers some control over the cache. For example, I believe that SDWebImage exposes the cache so you can purge it if you want (it also offers other advantages, too). There are probably lots of UIImageView categories that are more robust than AFNetworking's.


As an aside, rather than loading all 100 images up front, we often will employ lazy loading of images, only setting the image property of those image views that are visible at any given moment, and loading others as they scroll into view. And the UIImageView+AFNetworking category handles the graceful asynchronous loading of the images to ensure app responsiveness. If you're loading 100 images up front, it could adversely affect other network operations your app might need to do (if any).

Upvotes: 2

Related Questions