2012-06-29 3 views
1

지도에 사용자를 표시하는 앱을 여러 레스토랑 목록과 함께 만들고 있습니다. 사용자가 핀을 탭하면 주석의 좌표를 저장하고 사용자와 비교하여 좌표가 다른 지 확인합니다. 서로 다르다고 판단되면 사용자 좌표와 함께 비즈니스 좌표를 Google에 전송하여 길 찾기를 요청합니다. 이 코드는 정상적으로 작동하지만 그렇게하기 위해 메모리 누수의 원인이되는 몇 가지 변수를 선언해야했습니다. 나는 코드를 깨끗이하고 내가 실수 한 곳과 이것이 처리되어야하는 적절한 방법을 배우기를 바라고있다.MKAnnotation 및 NSString 메모리 누수 문제에 대한 조언

다음은 탭한 주석에서 좌표를 가져 오는 코드입니다. selectedAnnotation을 초기화하고 selectedAnnotation = [[MapLocation alloc] init];을 입력하여 viewDidLoad에 메모리를 할당하려고하면 여전히 메모리 누수로 표시됩니다. 그리고 참조 용으로 selectedAnnotation은 MapLocation (MKAnnotation을 준수) 변수이며 속성으로 (비 원자형, 보유 형) 및 @synthesize (d)가 있습니다.

나는 viewDidUnload에서 값을 nil로 설정하고 dealloc에서 해제 했으므로 아무런 메모리 문제가 없어야 만 메모리에 할당했다. 내가 뭘 놓치고 있니? 다음은 아래에 제공된 코드와 함께 viewDidLoad의 selectedAnnotation에 대한 메모리를 할당 할 때 내 메모리 누수에 대한 스크린 샷입니다. 이미 메모리를 할당하고 변수가 존재하는지 확인하면 왜 변수에 메모리를 다시 할당합니까? 이것은 내가 클릭하는 레스토랑 핀에서 발생하지만, 분명히 사용자의 핀에있는 것은 아닙니다.이 경우에 코드를 릴리스 할 것이기 때문입니다.

enter image description here

-(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에 표시 할 사용자 위치의 주소와 좌표를 추출합니다. 정보에 액세스하기 위해 필요한 모든 배열과 사전을 만들었지 만, 일단이 메서드의 코드 마지막 줄인 NSDictionary 변수 userLocation을 해제하려고 시도하면 해당 변수에 대한 메모리를 할당하고 해당 값을 savedUserLocation에 할당합니다. "[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; 
    } 
} 

모든 도움/제안/조언에 감사드립니다. 저는 제가 잘못하고있는 것에 대한 견해와 견해를 이해하고 싶습니다. 제가 꽤 괜찮은 생각을하고 있다고 생각했습니다.

selectedAnnotation = nil; 
[selectedAnnotation release]; 

이 당신이 selectedAnnotationnil에와 다음 그것에 release를 호출 설정되어 있기 때문에 메모리 누수가 발생합니다 : didSelectAnnotationView에서

답변

2

, 당신은이 코드가 있습니다. selectedAnnotation 그 시점에서 nil하고 nil에 대한 호출은 아무것도하지 않기 때문에

release에 대한 호출은 아무것도하지 않습니다.즉 할당 된 메모리는 절대로 해제되지 않지만 포인터 변수가 nil으로 설정되었으므로 didSelectAnnotationView이 다시 호출되면 코드에서 새 개체를 할당합니다.

당신은 두 문장의 순서 (nil에 다음 세트 release전화)을 전환해야합니다.

그러나, 당신은 단지 "를 선택 주석"에 대한 참조를 유지하기 위해 새로운 객체를 ALLOC 할 필요가 없습니다.

(보유 속성이 아닌) 일반 ivar을 선언하고 선택한 주석과 동일하게 설정하면 효과가 있습니다.

또한 맵보기에는 이미 사용할 수 있어야하는 selectedAnnotations이라는 속성이 있습니다 (따라서 자신의 ivar 또는 속성을 유지할 필요가 없습니다). 지도보기의 속성은 NSArray이지만 항상 0 또는 1 개의 개체가 포함됩니다. 그 countfetchedData에서 인덱스 0



에서 개체에 액세스하기 전에 확인해야합니다, 당신은 불필요한 alloc 호출에 의해 발생하는 여러 메모리 누수가 있습니다.
alloc을 호출 한 후 방금 메모리를 할당 한 포인터에 새 참조를 직접 할당하기 때문에 필요하지 않습니다.

예를 들어, userLocation은 for-loop 앞에 alloc '이고 루프 내부에서는 results 배열에있는 객체에 해당 변수를 직접 지정합니다.

이것은 원래 userLocation에 할당 된 메모리가 참조없이 버려진다는 것을 의미합니다. releaseuserLocation에 전화하려고하면 fetchedData에 코드로 할당되지 않은 개체를 해제하려고 시도하고 있습니다.

적어도 userLocation을 수정하려면 변수를 선언하고 alloc/init/release 개를 선언하면됩니다.

변수 addresstype (NSString)과 유사한 문제가 있습니다.

+0

실제로 selectedAnnotation의 경우 nil/release의 순서를 수정 한 후에도 문제가 계속 발생합니다. 그 이유는 alloc (포인터를 다시 할당 한 후)과 userLocation의 이유가 동일하기 때문입니다. 따라서 selectedAnnotation에 대해 ivar을 선언하고/init/release를 할당하지 마십시오 (또는 더 좋게는지도보기의 selectedAnnotations 속성 만 사용하십시오). – Anna

+0

'self.mapView.selectedAnnotation' 속성에 대한 머리를 주셔서 감사합니다. 내 모든 속성을 완벽하게 대체했습니다. 감사하게 생각합니다. 문자열에 대한 모든'alloc' 호출까지, 나는 그것들 중 2 개를 제거 할 수 있었지만, NSString * address = [[NSString alloc] initWithString : [userLocation objectForKey : @ "formatted_address"]]; ''MKAnnotations' 부제에 값을 보내기 때문에 추측하고 있습니다. 만약 내가'alloc '하지 않거나 for 루프 이후에'release' 시도를하면, 충돌이 발생합니다 :'- [CFString stringByStandardizingWhitespace] : 해제 된 인스턴스에 메시지 전송 됨' –

+0

savedUserLocation과 함께 메모리 관리 문제가 있음을 나타냅니다. 또한 MapLocation의 자막 속성이'copy' ('assign' 또는'retain'이 아닌)로 정의되어 있는지 확인하십시오. – Anna