【发布时间】:2013-05-22 21:27:06
【问题描述】:
我正在尝试学习如何在 iOS 6 中的地图上放置图钉。我有一个可以编译和运行但显然会泄漏内存的代码——但是当我释放(或自动释放)mapData 对象时,我的应用程序崩溃了。错误是
类AddressAnnotation 的实例0x1b7ac0 已被释放,而键值观察者仍向其注册。观察信息被泄露,甚至可能被错误地附加到其他对象上。在NSKVODeallocateBreak 上设置断点以在调试器中停止。
之前有一篇关于这个错误的帖子,也与 MapKit 相关:
Setting breakpoint at NSKVODeallocateBreak
但这对我没有帮助:
首先,我并不真正理解答案,但似乎答案与我的问题无关,因为我没有以任何方式设置观察者(我知道,就是这样!)例如,在我的代码中没有任何地方我有台词吗
[addressAnnotation addObserver:self forKeyPath:kSelectedAnnotationObserverKeyPath options:NSKeyValueObservingOptionNew context:@"selectedOrDeselected"];
或任何其他远程类似的东西,这被认为是问题。
话虽如此,我也应该说我不太了解观察者的概念——我当然创建了一个自定义类MapData,它是一个NSObject <MKAnnotation>,我想这也可能是一个问题的根源。但我基本上是一头雾水。
我尝试设置建议的符号断点,但这对我没有帮助:我看到我有一个BAD ACCESS 条件,但这就是我真正理解的全部!
我写的代码是这样的:
- (void) showRecordsOnMap
{
NSMutableArray *projectMapAnnotationsArray;
projectMapAnnotationsArray = [[NSMutableArray alloc] init];
int i = 0;
for (i = 0; i < [currentProject.recordArray count]; i++)
{
Record *record = [[[Record alloc] init]autorelease];
record = [currentProject.recordArray objectAtIndex:i];
CLLocationCoordinate2D newCoordinate;
newCoordinate.latitude = record.latitude;
newCoordinate.longitude = record.longitude;
int tag = 0;
NSString *title;
title = [[[NSString alloc] init] autorelease];
title = [NSString stringWithFormat:@"Record %d",record.record_ID];
NSString *subtitle;
subtitle = [[[NSString alloc] init] autorelease];
subtitle = [NSString stringWithFormat:@"Record %d",record.record_ID];
MapData *mapData =[[MapData alloc] initWithCoordinate:newCoordinate withTag:tag withTitle:title withSubtitle:title];
[projectMapAnnotationsArray addObject:mapData];
//[mapData release];
}
[projectMap addAnnotations:projectMapAnnotationsArray];
[projectMapAnnotationsArray release];
}
然后是下一个需要的位
- (MKAnnotationView *) mapView:(MKMapView *)mapView
viewForAnnotation:(MapData *)annotation
{
static NSString *record = @"record";
//the result of the call is being cast (MKPinAnnotationView *) to the correct
//view class or else the compiler complains
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[projectMap
dequeueReusableAnnotationViewWithIdentifier:record];
if(annotationView == nil)
{
annotationView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:record] autorelease];
}
//if((annotation).tag == 2) annotationView.pinColor = MKPinAnnotationColorRed;
//else annotationView.pinColor = MKPinAnnotationColorGreen;
annotationView.pinColor = MKPinAnnotationColorGreen;
//pin drops when it first appears
annotationView.animatesDrop=TRUE;
//tapping the pin produces a gray box which shows title and subtitle
annotationView.canShowCallout = YES;
return annotationView;
}
只要未释放 mapData 对象,此代码就会运行。但显然我需要释放它。作为另一个线索,如果我取消注释
// if((annotation).tag == 2) annotationView.pinColor = MKPinAnnotationColorRed;
// else annotationView.pinColor = MKPinAnnotationColorGreen;
我收到另一个错误:
[MKUserLocation 标记]:无法识别的选择器发送到实例 0x9fcb010 2013-05-22 23:05:13.726 Geo360[1175:c07] *** 由于未捕获的异常
'NSInvalidArgumentException'终止应用程序,原因:'-[MKUserLocation tag]:无法识别的选择器发送到实例0x9fcb010'
但在我看来,第二个错误对我来说是一个更简单的愚蠢,我至少知道如何去寻找。但是错误“AddressAnnotation”让我完全迷失了方向。非常感谢任何帮助!
编辑:
大家好 -- 感谢您抽出宝贵时间提供帮助。我仍然很困惑。附件是 AnnaKarenina 建议的 MapData 对象的代码。 Verbumdei 建议我将数组放在 ViewDidLoad 方法中作为一个强大的属性——我已经玩过了,但我也希望能够用一个可能有更多数据或更少数据的数组来刷新地图图钉,所以在我看来我每次都需要重新制作阵列。也许不是? AnnaKarenina 建议 MapData 中可能存在发布问题,现在我看到它有点怀疑我没有发布标签 - 但另一方面,这样做会产生警告!
再次感谢您的帮助...仍未解决。
MapData.h:
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
@interface MapData : NSObject <MKAnnotation>
{
NSString *_title;
NSString *subtitle;
NSUInteger tag;
CLLocationCoordinate2D _coordinate;
}
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
@property(nonatomic) NSUInteger tag;
// Getters and setters
- (id)initWithCoordinate:(CLLocationCoordinate2D)c withTag:(NSUInteger)t withTitle:(NSString *)tl withSubtitle:(NSString *)s;
@end
和MapData.m:
#import "MapData.h"
@implementation MapData
@synthesize coordinate;
@synthesize title;
@synthesize subtitle;
@synthesize tag;
-(id)initWithCoordinate:(CLLocationCoordinate2D)c withTag:(NSUInteger)t withTitle:(NSString *)tl withSubtitle: (NSString *)s
{
if(self = [super init])
{
coordinate = c;
tag = t;
title = tl;
subtitle = s;
}
return self;
}
- (void) dealloc
{
[title release];
[subtitle release];
[super dealloc];
}
@end
【问题讨论】:
-
为什么要在showRecordsOnMap方法的最后释放projectMapAnnotationsArray?
-
正如documentation for addAnnotations 所说,“地图视图保留了单个注释对象”,因此可以(并且您应该)发布 projectMapAnnotationsArray。崩溃可能是由于 MapData init 方法中的一些内存管理问题,例如在 mapData 上调用 release 会导致过度释放。发布 MapData init 方法的代码可能会有所帮助。
-
KVO 错误消息可能是与崩溃不同的问题,并且由于坐标无效(请参阅stackoverflow.com/questions/5872547/…)。
标签: objective-c ios6 memory-leaks mapkit