【问题标题】:nested NSAutoreleasePool嵌套的 NSAutoreleasePool
【发布时间】:2010-11-24 23:57:56
【问题描述】:

在我的 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) {

}

【问题讨论】:

  • 您在哪里以及如何实际下载图像?
  • 它在 [thisSlide saveFile:[slide objectForKey:@"file"]] 上完成,我从下载的文件创建 UIImage,然后使用 NSData 和 NSFileManager 保存在应用程序 Documents 文件夹中。

标签: objective-c iphone-sdk-3.0 nsautoreleasepool


【解决方案1】:

我很惊讶您的代码没有崩溃。 -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];
    }
}

【讨论】:

  • 您实际上是对的,关于 slidePool 的位置,但是代码从未崩溃。也感谢@finally 位。无论如何,它是否像我一样正确地应用了几个嵌套的自动释放池?
  • @cesofry: 是的,除了slidePool的alloc位置不对,没关系。
猜你喜欢
  • 1970-01-01
  • 2011-03-29
  • 2012-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多