1

我正在制作一个应用程序,在地图上显示用户以及多个餐厅列表。当用户点击一个图钉时,它会存储注释中的坐标,并将它们与用户进行比较,以确保它们不同。一旦确定它们不同,它就会将商家的坐标和用户的坐标一起发送给 Google 以请求方向。代码工作正常,但为了做到这一点,我必须以导致内存泄漏的方式声明一些变量。我希望清理代码并了解我出错的地方以及应该处理的正确方法。

所以下面是我从被点击的注释中获取坐标的代码。如果我尝试初始化 selectedAnnotation 并viewDidLoad通过 putselectedAnnotation = [[MapLocation alloc] init];然后分配它的内存,它仍然显示为内存泄漏。作为参考,selectedAnnotation是一个 MapLocation(符合 MKAnnotation)变量,作为一个属性,我拥有它(非原子,保留)和@synthesize(d)。

我以为只要在内存中分配,只要在viewDidUnload中将其值设置为nil并在dealloc中释放,就应该没有内存问题。我错过了什么?下面是我在 viewDidLoad 中为 selectedAnnotation 分配内存时内存泄漏的屏幕截图以及下面提供的代码。如果我已经分配了内存,并检查变量是否存在,为什么还要为变量分配内存?这发生在我点击的任何餐厅 pin 上,但显然不是在用户的 pin 上,因为在这种情况下我有释放它的代码。

在此处输入图像描述

-(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什么都不做,因为selectedAnnotationnil那个时候,调用nil什么也不做。这意味着已分配的内存永远不会释放,但由于指针变量已设置为nil,当didSelectAnnotationView再次调用时,您的代码会分配一​​个新对象。

您应该切换两个语句的顺序(release 调用然后设置为nil)。

但是,您不需要分配新对象只是为了保留对“选定注释”的引用。

声明一个常规 ivar(不是保留属性)并将其设置为等于所选注释应该可以工作。

此外,地图视图已经有一个名为的属性selectedAnnotations,您应该可以使用它(因此您不需要维护自己的 ivar 或属性)。地图视图的属性是 anNSArray但总是包含 0 或 1 个对象。count在访问索引 0 处的对象之前,请务必检查它。



在中,您有几个由不必要的调用fetchedData引起的内存泄漏。 它们不是必需的,因为在调用之后,您将直接为刚刚为其分配内存的指针分配一个新的引用。alloc
alloc

例如,userLocationis alloc'd 在 for 循环之前,但在循环内部,您直接将该变量指向results数组中的一个对象。

这意味着最初分配给userLocation它的内存在没有引用的情况下被废弃。当您尝试调用releaseon 时userLocation,它正在尝试释放未由 in 中的代码分配的对象fetchedData

至少要修复userLocation,只需声明变量而不是alloc//它initrelease

变量addresstype( NSString) 有类似的问题。

于 2012-06-29T13:43:13.750 回答