1

複数のレストランのリストとともにユーザーを地図上に表示するアプリを作成しています。ユーザーがピンをタップすると、注釈からの座標が保存され、ユーザーと比較されて異なることが確認されます。それらが異なると判断されると、ビジネスの座標とユーザーの座標をGoogleに送信して道順をリクエストします。コードは正常に機能していますが、そのためには、メモリリークを引き起こす方法でいくつかの変数を宣言する必要がありました。私はコードをクリーンアップして、どこでエラーが発生したか、そしてこれを適切に処理する方法を学びたいと思っています。

以下は、タップされた注釈から座標を取得するための私のコードです。selectedAnnotationを初期化し、そのメモリを次のように割り当てようとするviewDidLoadselectedAnnotation = [[MapLocation alloc] init];、メモリリークとして表示されます。参考までselectedAnnotationに、MapLocation(MKAnnotationに準拠)変数があり、プロパティとして(nonatomic、retain)および@synthesize(d)があります。

メモリに割り当てている限り、viewDidUnloadで値をnilに設定し、deallocで解放している限り、メモリの問題は発生しないはずだと思いました。私は何が欠けていますか?以下は、viewDidLoadでselectedAnnotationにメモリを割り当てたときのメモリリークのスクリーンショットと、以下に示すコードです。すでにメモリを割り当てており、変数が存在することを確認した場合、なぜ変数にメモリを再度割り当てるのでしょうか。これは、クリックしたレストランのピンで発生しますが、ユーザーのピンでは発生しません。その場合、リリースするコードがあるためです。

ここに画像の説明を入力してください

-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
     //NSLog(@"Selected annotation view");

     // if we don't have the place holder already allocated
     // lazy load the MapLocation placeholder variable
     if(!selectedAnnotation)
     {
         selectedAnnotation = [[MapLocation alloc] init];
     }

     // save the annotation clicked 
     selectedAnnotation = view.annotation;

     // if the annotation selected was is the same as the user's location
     if((selectedAnnotation.coordinate.latitude == savedUserLocation.coordinate.latitude) &&      (selectedAnnotation.coordinate.longitude == savedUserLocation.coordinate.longitude))
     {
         // set it to nil and release it
         selectedAnnotation = nil;
         [selectedAnnotation release];
     } 
}

私は以下の方法でメモリの問題で同様の問題を抱えています。GoogleからJSONデータを取り込んで、AnnotationViewに表示するユーザーの場所のアドレスと座標を抽出します。情報にアクセスするために必要なすべての配列と辞書を作成しましたが、それらにメモリを割り当て、それらの値をsavedUserLocationに割り当てたら、NSDictionary変数userLocationを解放しようとすると、このメソッドのコードの最後の行としても、が原因でアプリがクラッシュし"[CFDictionary release]: message sent to deallocated instance 0x83ccb60"ます。ポインタを介して値を設定しているためだと確信していますsavedUserLocation。メモリが解放されると、その情報は存在しなくなります。そのため、情報にアクセスできる場所にメモリを割り当て/解放する適切な方法は何でしょうか。メモリリークを引き起こさずに?私も使ってみましたautorelease、しかし同じ問題が続く。

これがユーザーピンを配置するコードです。

    - (void)fetchedData:(NSData *)responseData 
{
    //parse out the json data

   NSError *error;
    NSDictionary *json = [NSJSONSerialization 
                          JSONObjectWithData:responseData //1

                          options:kNilOptions 
                          error:&error];

    NSArray *results = [json objectForKey:@"results"]; //2
    NSUInteger counter = [results count];

NSDictionary *userLocation = [[NSDictionary alloc] init];
//NSString *address = [[NSString alloc] init];                           
for(NSUInteger i=0; i < counter; i++)
{
    userLocation = [results objectAtIndex:i];

    // 2) Get the funded amount and loan amount
    NSString *address = [[NSString alloc] initWithString:[userLocation objectForKey:@"formatted_address"]];
    NSArray *types = [userLocation objectForKey:@"types"];
    NSDictionary *geometry = [userLocation objectForKey:@"geometry"];
    NSDictionary *location = [geometry objectForKey:@"location"];
    float lat = [[location objectForKey:@"lat"] floatValue];
    float lon = [[location objectForKey:@"lng"] floatValue];

    CLLocationCoordinate2D newCoordinates;
    newCoordinates.latitude = lat;
    newCoordinates.longitude = lon;

    // count how many types there are
    NSUInteger numberOfTypes = [types count];
    NSString *type = [[NSString alloc] init];

    for(NSUInteger j=0; j < numberOfTypes; j++)
    {
        type = [types objectAtIndex:j];

        if([type rangeOfString:@"street_address" options:NSCaseInsensitiveSearch].location != NSNotFound)
        {
            NSLog(@"%@", address);  
            if(!savedUserLocation)
            {
                savedUserLocation = [[MapLocation alloc] init];
            }

            [savedUserLocation setTitle:@"You are here!"];
            [savedUserLocation setSubtitle:address];
            [savedUserLocation setCoordinate:newCoordinates];
        }
    }
}


// determine which location is closest to the user by calling this function
MapLocation *closestLocation = [self determineClosestLocationToUser:allLocations locationOfUser:savedUserLocation];

// send in the user location and the closest store to them to determine appropriate zoom level and 
// to center the map between the two
[self determineMapCenterAndZoomLevelFromUser:savedUserLocation andClosestLocation:closestLocation];

if(!pinDropped)
{
    // add the annotation to the map and then release it
    [mapView addAnnotation:savedUserLocation];
    pinDropped = true;
    }
}

ありとあらゆるヘルプ/提案/アドバイスをありがとう。私はそれをかなりよく理解していると思ったので、私が間違っていることの要点を本当に理解したいと思います。

4

1 に答える 1

2

にはdidSelectAnnotationView、次のコードがあります。

selectedAnnotation = nil;
[selectedAnnotation release];

selectedAnnotationに設定しnilから呼び出すため、これによりメモリリークが発生しますrelease

その時点で があり、 への呼び出しは何releaseもしないため、 への呼び出しは何もしません。これは、割り当てられたメモリが決して解放されないことを意味しますが、ポインター変数が に設定されているため、が再び呼び出されると、コードは新しいオブジェクトを割り当てます。selectedAnnotationnilnilnildidSelectAnnotationView

2 つのステートメントの順序を入れ替える必要があります (release 最初に呼び出してから設定しnilます)。

ただし、「選択した注釈」への参照を保持するためだけに、新しいオブジェクトを割り当てる必要はありません。

通常の ivar (保持プロパティではない) を宣言し、選択した注釈と等しく設定するだけで機能します。

さらに、マップ ビューには、selectedAnnotations使用できる必要があるという名前のプロパティが既にあります (そのため、独自の ivar またはプロパティを維持する必要はありません)。マップ ビューのプロパティは ですが、NSArray常に 0 または 1 個のオブジェクトが含まれます。countインデックス 0 のオブジェクトにアクセスする前に、必ず確認してください。



では、不要な呼び出しfetchedDataが原因でいくつかのメモリ リークが発生しています。 を呼び出した後、メモリを割り当てたばかりのポインターに新しい参照を直接割り当てるため、それらは必要ありません。alloc
alloc

たとえば、for ループの前userLocationalloc'd が実行されますが、ループ内では、その変数をresults配列内のオブジェクトに直接ポイントします。

これは、元々割り当てられていたメモリがuserLocation参照されずに放棄されることを意味します。を呼び出そうとするとreleaseuserLocationのコードによって割り当てられていないオブジェクトを解放しようとしていますfetchedData

少なくとも を修正するには、変数を宣言するだけで//userLocationしないでください。allocinitrelease

変数addresstype( NSString) にも同様の問題があります。

于 2012-06-29T13:43:13.750 に答える