嵌套 NSAutoreleasePool

发布于 2024-10-04 03:54:19 字数 1909 浏览 8 评论 0原文

在我的 iPad 应用程序之一中,我使用 json 字符串远程构建数据库,然后转换为 NSArray 以插入核心数据,然后在 ipad 上下载大约 600Mb 的图像。所有这些都是在后台线程中创建的,从一开始就导致一些内存问题。 我解决了在操作中嵌套 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) {

}

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

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

鹊巢 2024-10-11 03:54:19

我很惊讶你的代码没有崩溃。 -drain 在引用计数环境中的行为与 -release 相同,因此下面的 over 释放池

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

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];
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文