1

I am downloading cover images uploaded by App.net users. App.net requires these cover images to be at least 960 pixels wide. I fetch them with a simple AFImageRequestOperation:

NSURLRequest *urlRequest = [NSURLRequest requestWithURL:URL];
AFImageRequestOperation *imageRequestOperation = [AFImageRequestOperation imageRequestOperationWithRequest:urlRequest success:^(UIImage *image) {
    if (completionHandler) {
        completionHandler(image); // Load image into UI...
    }
}];
[self.fetchQueue addOperation:imageRequestOperation];

This is working, no memory spikes.

I want to cache the authenticated users' images so users don't have to download them each time the app opens. As soon as I archive the downloaded image to disk, I get huge spikes in memory. For example, my cover image is currently 3264 x 2448 pixels. When downloaded on my Mac it comes to around 1,3 MB. However, as soon as I create a NSData object with either UIImagePNGRepresentation(image) or via TMCache's setObject:forKey: method, the app's used memory spikes to around 60,0 MB.

For clarity, This is all I'm doing to write the file to disk:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    NSURL *fileURL = ... //  URL of file in "/Application Support" 
    NSData *imageData = UIImagePNGRepresentation(imageToSave);
    [imageData writeToURL:fileURL atomically:YES];
});

Can anyone tell me what is going on? Why is a 1,3 MB being extrapolated into almost sixty times that. How can I avoid this massive and potentially crippling inflation. This is one image, what if the user opens several profiles, each with a cached image?

Jeremy
  • 1
  • 85
  • 340
  • 366
Shawn Throop
  • 1,281
  • 1
  • 13
  • 28

1 Answers1

1

The image dimensions are what have the greatest bearing on memory usage. For a given image size (regardless of PNG, JPG), the memory usage is pretty much the same and is given by: width x height x 4 bytes.

A cover image of 3264x2448 would decode to roughly 32MB. Perhaps the atomic write explains the doubling you see.

Spikes like this may be unavoidable if that's the size of the image you need to work with. The important thing is to make sure the memory usage isn't growing without bound. When you run the app and look at the memory instrument gauge, does it eventually go down as your app does its work? You can also try wrapping the image-writing code in an @autoreleasepool.

azsromej
  • 1,619
  • 13
  • 15
  • Very helpful, thanks. What I find strange is that the UIImage doesn't take up so much memory, only converting it to NSData does. I used your information and just download a smaller image and cache that. If people tap the image I download the full thing in UIImage form. All data is being released when the view controller is destroyed, and after some time it goes down anyways. Could the background thread that saves it be retaining the NSData object? I tried an @autoreleasepool but it seemed to have no effect. – Shawn Throop Jul 29 '14 at 01:19
  • I think what you're seeing is the deferred loading/decoding that iOS does with images. When you download an image and then create a UIImage with imageWithContentsOfFile:, nothing is decoded (yet). Drawing the image or setting it on a UIImageView would cause that to happen, and memory use would go up. Getting a data representation seems similar. If you try the scenario you mentioned with a user viewing several profiles, what kind of memory usage do you see over time? – azsromej Jul 29 '14 at 01:57