Search code examples
iphonememoryipadmemory-managementnsdata

Help with memory problem on iOS/iPad


In my app, I have a bunch of different image packs to download. The images are downloaded from my website one by one. The packs contain anywhere from 100-1500 images and each image is about 100KB-200KB.

When downloading the images, I have a method that selects the images to download, then I have a second method that does the actual downloading based on parameters sent from the main method. Here is the code for the download method:

-(BOOL) downloadImageName:(NSString *)imageName ImageGroup:(NSString *)imageGroup AndRow:(int)row {

    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                                     NSUserDomainMask, YES);
    NSString *docsPath = [paths objectAtIndex:0];

    NSURL *downloadURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://www.website.com/%@_0001.jpg",imageName]];
    NSData *data = [NSData dataWithContentsOfURL:downloadURL];
    NSString *savePath = [NSString stringWithFormat:@"%@/%@^%@_%@.jpg",docsPath,currentServerCycle,imageGroup,imageName];
    BOOL downloaded = [data writeToFile:savePath atomically:YES];

    if (downloaded) 
             return YES; 
    }

    else {
    return NO;
    }
}

The problem I am having is this:

When I run this with performance tools looking at allocations I'm seeing that the app is keeping mallocs (NSConcreteData) each time an image is downloaded and only releasing them when the main method (the one calling this download method) completes. Thats fine for the smaller image packs, but the larger ones are obviously crashing after my total allocations hit something like 300+MB (the normal amount of allocations in my app is about 3mb).

They arent leaking, because once the image pack is downloaded and the method ends, all the mallocs are gone.

I have tried manually allocing and releasing the NSData *data but it has no effect.


Solution

  • Perhaps the autorelease pool the objects are in is not being drained until the main method returns. You might try adding NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; at the beginning of your download method, then [pool drain]; right before you return from the download method. You need to make sure you release the pool before you return no matter where you return otherwise you'll leak the pool.

    Also, just as a point of standard Objective-C style, your method should be named:

    • (BOOL)downloadImageName:(NSString *)imageName imageGroup:(NSString *)imageGroup andRow:(int)row

    with lowercase letters to start the "imageGroup:" and "andRow:" argument names.