views:

120

answers:

2

I am have an app I am writing that will need to download alot of images, possibly 10,000. Right now I can get to about 3000 before I run out of memory and the app crashes, just depends on the image files sizes. I am downloading them on a background thread and showing the progress to the user.

I wrote a helper class thatI am accessing to do this and wondering if that is where my problems lie and I am just leaking memory.

Here is my loop that downloading the images - this is running on a background thread, this is all inside an NSAutoReleasePool:

for (int j=0; j < [items count]; j++)
            {

                ImagesHelper *helper = [[ImagesHelper alloc]init];
                [helper downloadImages: [[items objectAtIndex:j] valueForKey:@"ItemSKU"] withManufacturer: [[manufacturers objectAtIndex:i] ManufacturerID]];
                [helper release];

                if (j%50==0) { //this notifies the user of progress
                    statusMessage = [NSString stringWithFormat:@"Downloading images: %@.jpg (%d of %d)", [[items objectAtIndex:j] valueForKey:@"ItemSKU"],j+1, [items count]];
                    [self performSelectorOnMainThread:@selector(setStatus) withObject:nil waitUntilDone:YES];
                }
            }

Here is my helper class:

-(void) downloadImages:(NSString *)ItemSKU withManufacturer: (NSString *) aManufacturerID{

    NSData *imageData = nil;
    NSData *imageDataLarge=nil;
    NSString *fileName = [NSString stringWithFormat:@"%@_tn.jpg", [ItemSKU  stringByReplacingOccurrencesOfString:@" " withString:@""]];
    NSString *fileNameLarge = [NSString stringWithFormat:@"%@_lg.jpg", [ItemSKU stringByReplacingOccurrencesOfString:@" " withString:@""]];

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsPath = [paths objectAtIndex:0];
    NSString *savePath = [documentsPath stringByAppendingPathComponent:fileName];
    NSString *savePathLarge = [documentsPath stringByAppendingPathComponent:fileNameLarge];

    /* go get the image */
    NSString *URL = [NSString stringWithFormat:kProductImagesURL,aManufacturerID, fileName];
    NSString *URLLarge = [NSString stringWithFormat:kProductImagesURL,aManufacturerID, fileNameLarge];

    NSLog(@"Going to get the file: %@",URL);
    imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:URL]];
    if (imageData!=nil) {
        [imageData writeToFile:savePath atomically:YES];
    }

    imageDataLarge = [NSData dataWithContentsOfURL:[NSURL URLWithString:URLLarge]];
    if (imageDataLarge!=nil) {
        [imageDataLarge writeToFile:savePathLarge atomically:YES];
    }

    imageData = nil;
    imageDataLarge=nil;
}

Still trying to get ahold of some of these concepts.

+1  A: 

Have you tried doing Build and Analyze? That might help. Also play around with Instruments. Lastly, I'd recommend using NSOperationQueue for these. That way you can do them in parallel. Additionally, your AutoReleasePool might not autorelease anything until control returns to the main thread.

tuzzolotron
yeah, it looks like after I go back to the main thread everything gets released. I'll have to break these into small chunks and run a series of background threads.
Slee
+1 for the operation queue. It was built for stuff like this.
Dave DeLong
A: 

Every single one of those factory methods you're using (stringWith*, stringBy*, URLwith*, dataWith*, etc.) is returning an autoreleased object whose pool won't empty until the end of the loop. Try alloc init on the stuff and then release as soon as you're finished with it. You should see better results.

sevenflow
seems to be helping - thank you!
Slee