Reputation: 3704
In one of my applications for iPad I am building up the db remotely using a json string then converted to NSArray to be insert in core data and then I donwload around 600Mb of images on the ipad. All this is created in a background thread causing from the beginning some memory issue. I get hold of the problem nesting 3 different NSAutoreleasePool in the operation and releasing each of them at a convenient point. I got no error, nor leak, nor warning. I was just wondering if it is a good way of doing it or I just miss something.
Here a schematic example (the real code is quite long):
- (void)main{
@try {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // first pool
[managedOC lock];
NSArray *results = [self loadEntitiesWithGroupName:@"Project" andName:@"projects"];
NSAutoreleasePool *prjPool; // second pool
for (NSDictionary *thisResult in results) {
prjPool = [[NSAutoreleasePool alloc] init];
Project *prj = [[Project alloc] initWithEntity:[NSEntityDescription entityForName:@"Project" inManagedObjectContext:self.managedOC] insertIntoManagedObjectContext:self.managedOC];
prj.name = [thisResult objectForKey:@"name"];
[prj saveThumbnail:[thisResult objectForKey:@"thumbnail"]];
//Slides. Those are the images that take so mutch space.
NSArray *slides = [thisResult objectForKey:@"slides"];
NSAutoreleasePool *slidePool; // third pool
if(slides != kCFNull){
slidePool = [[NSAutoreleasePool alloc] init];
for(NSDictionary *slide in slides){
Slide *thisSlide = [[Slide alloc] initWithEntity:[NSEntityDescription entityForName:@"Slide" inManagedObjectContext:self.managedOC] insertIntoManagedObjectContext: self.managedOC];
thisSlide.path = prj.path;
[thisSlide saveFile:[slide objectForKey:@"file"]];
[prj addSlidesObject:thisSlide];
[thisSlide release];
[slidePool drain];
}
}
[prj release];
[result release];
[prjPool drain];
}
[self.managedOC unlock];
[totResult release];
[pool drain];
}
@catch (NSException * e) {
}
Upvotes: 0
Views: 766
Reputation: 86651
I'm surprised your code doesn't crash. -drain
behaves the same as -release
in the reference counted environment, so the following over releases the pool
slidePool = [[NSAutoreleasePool alloc] init]; // this is in the wrong place
for(NSDictionary *slide in slides){
Slide *thisSlide = [[Slide alloc] initWithEntity:[NSEntityDescription entityForName:@"Slide" inManagedObjectContext:self.managedOC] insertIntoManagedObjectContext: self.managedOC];
thisSlide.path = prj.path;
[thisSlide saveFile:[slide objectForKey:@"file"]];
[prj addSlidesObject:thisSlide];
[thisSlide release];
[slidePool drain];
}
Unless there is only one object in the slides
collection. You need this:
for(NSDictionary *slide in slides){
slidePool = [[NSAutoreleasePool alloc] init]; // this is in the right place
Slide *thisSlide = [[Slide alloc] initWithEntity:[NSEntityDescription entityForName:@"Slide" inManagedObjectContext:self.managedOC] insertIntoManagedObjectContext: self.managedOC];
thisSlide.path = prj.path;
[thisSlide saveFile:[slide objectForKey:@"file"]];
[prj addSlidesObject:thisSlide];
[thisSlide release];
[slidePool drain];
}
Other than that, you have the right general idea.
You should drain your outermost pool in the finally block of your exception handler so that it is not skipped if an exception is raised i.e. you should do this:
- (void)main{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // first pool
@try {
// Do al your stuff
}
@catch (NSException * e) {
}
@finally
{
[pool drain];
}
}
Upvotes: 1