我正在创建一个应用程序,在地图上显示用户以及多个餐馆列表。当用户点击一个图钉时,它会存储注释中的坐标并将它们与用户进行比较,以确保它们不同。一旦确定它们不同,它就会将业务的坐标以及用户的坐标发送给Google以请求路线。代码工作正常,但为了它这样做,我不得不以导致内存泄漏的方式声明一些变量。我希望清理代码并了解我的错误以及应该处理的正确方法。
以下是我从获取的注释中获取坐标的代码。如果我尝试初始化selectedAnnotation并通过放置viewDidLoad
在selectedAnnotation = [[MapLocation alloc] init];
中分配它的内存然后它仍然显示为内存泄漏。作为参考,selectedAnnotation
是MapLocation(符合MKAnnotation)变量,作为属性,我有它(非原子,保留)和@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
,但同样的问题仍然存在。
以下是放置用户pin的代码。
- (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;
}
}
感谢您提供的所有帮助/建议/建议。我真的很想了解我做错了什么,我觉得我对它有很好的把握。
答案 0 :(得分:2)
在didSelectAnnotationView
中,您有以下代码:
selectedAnnotation = nil;
[selectedAnnotation release];
这会导致内存泄漏,因为您将selectedAnnotation
设置为nil
,然后将release
设置为{}}。
对release
的调用不执行任何操作,因为此时selectedAnnotation
为nil
且对nil
的调用不执行任何操作。这意味着从未释放已分配的内存,但由于指针变量已设置为nil
,因此再次调用didSelectAnnotationView
时,您的代码将分配一个新对象。
您应该切换两个语句的顺序(先调用release
,然后然后将设置为nil
)。
然而 ,您不需要分配新对象只是为了保持对“选定注释”的引用。
声明一个常规的ivar(不是保留属性)并将其设置为等于所选的注释应该有效。
此外,地图视图已经有一个名为selectedAnnotations
的属性,您应该可以使用它(因此您不需要维护自己的ivar或属性)。地图视图的属性是NSArray
,但始终包含0或1个对象。在访问索引0处的对象之前,请务必检查其count
。
在fetchedData
中,由于不必要的alloc
调用而导致多次内存泄漏
它们不是必需的,因为在调用alloc
之后,您将直接为刚刚为其分配内存的指针分配新的引用。
例如,userLocation
在for循环之前是alloc
',但是在循环内部,您直接将该变量指向results
数组中的对象。
这意味着最初为userLocation
分配的内存将被放弃而不参考它。当您尝试在release
上调用userLocation
时,它会尝试释放未由fetchedData
中的代码分配的对象。
要至少修正userLocation
,只需声明变量,而不是alloc
/ init
/ release
。
变量address
和type
(NSString
)也有类似的问题。