0

iPad用のアプリケーションの1つで、json文字列を使用してリモートでdbを構築し、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) {

}
4

1 に答える 1

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コレクションにオブジェクトが1つしかない場合を除きます。あなたはこれを必要とします:

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];
    }
}
于 2010-11-24T15:57:56.987 に答える