0

編集:プロジェクトでARCを使用しています

次のように plist から注釈をロードします。

[NSThread detachNewThreadSelector:@selector(loadPList) toTarget:self withObject:nil];

...

- (void) loadPList
{

    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:@"test.plist"];

    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; // memory leak here

    NSMutableArray *annotations = [[NSMutableArray alloc]init];


    dispatch_async(dispatch_get_main_queue(), ^{


        NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ;
        [ annotationsToRemove removeObject:mapView.userLocation ] ;
        [ mapView removeAnnotations:annotationsToRemove ] ;



        if ([[NSUserDefaults standardUserDefaults] boolForKey:@"blackKey"])
        {

            NSArray *ann = [dict objectForKey:@"Black"];

            for(int i = 0; i < [ann count]; i++) {

                NSString *coordinates = [[ann objectAtIndex:i] objectForKey:@"Coordinates"];

                double realLatitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:1] doubleValue];
                double realLongitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:0] doubleValue];

                MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
                CLLocationCoordinate2D theCoordinate;
                theCoordinate.latitude = realLatitude;
                theCoordinate.longitude = realLongitude;

                myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);        
                myAnnotation.title = [[ann objectAtIndex:i] objectForKey:@"Name"];
                myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:@"Address"];
                myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:@"Icon"];

                [mapView addAnnotation:myAnnotation];
                [annotations addObject:myAnnotation];

            }

        }   


    });


}

すべて正常に読み込まれますが、メモリ リーク ツールでリークが表示されます。

リークスクリーンショット

4

3 に答える 3

2

@autoreleasepoolメソッドの先頭にを配置する必要があります。そのdictionaryWithContentsOfFile:呼び出しをメソッドの外側に置くと、プールなしで自動解放されたオブジェクトが作成されるため、リークが発生します。スレッド プログラミング ガイドによると:

アプリケーションでマネージ メモリ モデルを使用している場合は、スレッド エントリ ルーチンで最初に自動解放プールを作成する必要があります。同様に、この自動解放プールを破棄することは、スレッドで最後に行う必要があります。

また、グローバル キューを使用するのNSThreadではなく、plist をロードするために使用する理由をお尋ねしてもよろしいですか? スレッド分離内にネストされているdispatch_async()ことはあまりないので、興味があります。dispatch_async()

編集:

スレッド/GCD ハイブリッドを妨害せずにメモリ リークを修正するには、次のようにメソッドを呼び出します。

[NSThread detachNewThreadSelector:@selector(loadPList) toTarget:self withObject:nil];

そして、次のように実装します。

- (void) loadPList
{
    @autoreleasepool {
        NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
        NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:@"test.plist"];

        NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; // memory leak here

        NSMutableArray *annotations = [[NSMutableArray alloc]init];


        dispatch_async(dispatch_get_main_queue(), ^{

            NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ;
            [ annotationsToRemove removeObject:mapView.userLocation ] ;
            [ mapView removeAnnotations:annotationsToRemove ] ;

            if ([[NSUserDefaults standardUserDefaults] boolForKey:@"blackKey"])
            {
                NSArray *ann = [dict objectForKey:@"Black"];

                for(int i = 0; i < [ann count]; i++) 
                {
                    NSString *coordinates = [[ann objectAtIndex:i] objectForKey:@"Coordinates"];

                    double realLatitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:1] doubleValue];
                    double realLongitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:0] doubleValue];

                    MyAnnotation *myAnnotation = [[MyAnnotation alloc] init];
                    CLLocationCoordinate2D theCoordinate;
                    theCoordinate.latitude = realLatitude;
                    theCoordinate.longitude = realLongitude;

                    myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);        
                    myAnnotation.title = [[ann objectAtIndex:i] objectForKey:@"Name"];
                    myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:@"Address"];
                    myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:@"Icon"];

                    [mapView addAnnotation:myAnnotation];
                    [annotations addObject:myAnnotation];
                }
            }   
        }
        );
    }
}
于 2012-09-29T17:23:00.490 に答える
0

他に何もないとしても、自動解放プールが必要です。のドキュメントから引用するとdetachNewThreadSelector、「メソッドaSelectorは、新しく切り離されたスレッドの自動解放プールを設定し、終了する前にそのプールを解放する責任があります。」

個人的には、おそらくloadPlistではなく GCD を介して呼び出すだけdetachNewThreadSelectorで、自動解放プールについて心配する必要はありません。

dispatch_async(get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self loadPlist];
});
于 2012-09-28T13:52:15.720 に答える
-1
NSMutableArray *annotations = [[NSMutableArray alloc]init]; // Never released
NSMutableArray * annotationsToRemove = [ mapView.annotations mutableCopy ] ; // Never released
MyAnnotation *myAnnotation = [[MyAnnotation alloc] init]; // Never released

メソッドは次のようになります。

- (void) loadPList {
    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:@"test.plist"];
    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; // memory leak here
    NSMutableArray *annotations = [[[NSMutableArray alloc] init] autorelease];
    dispatch_async(dispatch_get_main_queue(), ^{
        NSMutableArray * annotationsToRemove = [[mapView.annotations mutableCopy] autorelease];
        [annotationsToRemove removeObject:mapView.userLocation] ;
        [mapView removeAnnotations:annotationsToRemove] ;
        if ([[NSUserDefaults standardUserDefaults] boolForKey:@"blackKey"])
        {

            NSArray *ann = [dict objectForKey:@"Black"];

            for(int i = 0; i < [ann count]; i++) {

                NSString *coordinates = [[ann objectAtIndex:i] objectForKey:@"Coordinates"];

                double realLatitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:1] doubleValue];
                double realLongitude = [[[coordinates componentsSeparatedByString:@","] objectAtIndex:0] doubleValue];

                MyAnnotation *myAnnotation = [[[MyAnnotation alloc] init] autorelease];
                CLLocationCoordinate2D theCoordinate;
                theCoordinate.latitude = realLatitude;
                theCoordinate.longitude = realLongitude;

                myAnnotation.coordinate=CLLocationCoordinate2DMake(realLatitude,realLongitude);
                myAnnotation.title = [[ann objectAtIndex:i] objectForKey:@"Name"];
                myAnnotation.subtitle = [[ann objectAtIndex:i] objectForKey:@"Address"];
                myAnnotation.icon = [[ann objectAtIndex:0] objectForKey:@"Icon"];

                [mapView addAnnotation:myAnnotation];
                [annotations addObject:myAnnotation];

            }
        }   
    });
}
于 2012-09-28T12:32:31.803 に答える