вложенный NSAutoreleasePool - PullRequest
       6

вложенный NSAutoreleasePool

0 голосов
/ 24 ноября 2010

В одном из моих приложений для iPad я создаю базу данных удаленно, используя строку json, затем преобразую в NSArray для вставки в основные данные, а затем загружаю около 600 Мб изображений на ipad.Все это создается в фоновом потоке, вызывая с самого начала некоторые проблемы с памятью.Я справился с проблемой, вложив в операцию 3 разных NSAutoreleasePool и выпустив каждый из них в удобной точке.Я не получил ни ошибки, ни утечки, ни предупреждения.Мне было просто интересно, если это хороший способ сделать это, или я просто что-то пропустил.

Вот схематический пример (реальный код довольно длинный):

- (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) {

}

1 Ответ

1 голос
/ 24 ноября 2010

Я удивлен, что твой код не падает.-drain ведет себя так же, как и -release в среде с подсчетом ссылок, поэтому следующее перезагружает пул

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];
}

Если только в коллекции slides нет только одного объекта.Вам нужно это:

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];
}

Кроме этого, у вас есть правильная общая идея.

Вы должны истощить свой самый внешний пул в блоке finally вашего обработчика исключений, чтобы он не пропускался при возникновении исключения, т.е. вы должны сделать это:

- (void)main{

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // first pool

    @try {

        // Do al your stuff
    }
    @catch (NSException * e) {

    }
    @finally
    {
        [pool drain];
    }
}
...