Objective c 在iOS6中在地图上放置PIN后崩溃

Objective c 在iOS6中在地图上放置PIN后崩溃,objective-c,ios6,memory-leaks,mapkit,Objective C,Ios6,Memory Leaks,Mapkit,我正在尝试学习如何在iOS 6中在地图上放置图钉。我有一段代码可以编译和运行,但显然会泄漏内存——但当我释放(或自动释放)mapData对象时,我的应用程序崩溃了。错误是 类AddressAnnotation的实例0x1b7ac0已解除分配,而键值观察员仍在该实例中注册。观测信息被泄露,甚至可能被错误地附加到其他物体上。在NSKVODeallocateBreak上设置断点,使其在调试器中停止 之前有一篇关于这个错误的帖子,也是关于MapKit的: 但这对我没有帮助: 首先,我并不真正理解答案,

我正在尝试学习如何在iOS 6中在地图上放置图钉。我有一段代码可以编译和运行,但显然会泄漏内存——但当我释放(或自动释放)mapData对象时,我的应用程序崩溃了。错误是

AddressAnnotation
的实例
0x1b7ac0
已解除分配,而键值观察员仍在该实例中注册。观测信息被泄露,甚至可能被错误地附加到其他物体上。在
NSKVODeallocateBreak
上设置断点,使其在调试器中停止

之前有一篇关于这个错误的帖子,也是关于MapKit的:

但这对我没有帮助:
首先,我并不真正理解答案,但答案似乎与我的问题无关,因为我没有以任何方式设置观察者(我知道,就是这样!)例如,我的代码中没有行

[addressAnnotation addObserver:self forKeyPath:kSelectedAnnotationObserverKeyPath options:NSKeyValueObservingOptionNew context:@"selectedOrDeselected"];
或者任何其他稍微相似的东西,这被认为是问题所在

话虽如此,我也应该说我并不真正理解观察者的概念——我当然创建了一个自定义类
MapData
,它是一个
NSObject
,我想这也可能是问题的根源。但我基本上是被铅垂惊呆了

我曾尝试设置建议的符号断点,但这对我没有帮助:我看到我有一个
坏访问
条件,但这就是我真正理解的

我编写的代码如下:

- (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];

}
只要不释放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
'

但在我看来,第二个错误对我来说是一个更简单的愚蠢,我至少知道如何去发现它。但是错误“class
AddressAnnotation
”让我完全不知所措。非常感谢您的帮助


编辑:

大家好,谢谢你们抽出时间来帮忙。我还是很困惑。附件是安娜卡列尼娜建议的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
#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

当注释显示在地图中时,不能释放MapData对象。如果要释放MapData对象,需要首先从地图中删除注释

我建议您将projectMapAnnotationsArray作为视图控制器的强属性。在
viewDidLoad
方法中分配它。然后您可以在视图控制器的
dealloc
方法中释放它


showRecordsOnMap
方法中,只需将对象添加到projectMapAnnotationsArray,而无需释放数组本身。

当注释显示在地图中时,不能释放MapData对象。如果要释放MapData对象,需要首先从地图中删除注释

我建议您将projectMapAnnotationsArray作为视图控制器的强属性。在
viewDidLoad
方法中分配它。然后您可以在视图控制器的
dealloc
方法中释放它


showRecordsOnMap
方法中,您只需将对象添加到projectMapAnnotationsArray,而无需释放数组本身。

关于EXC\u BAD\u ACCESS的崩溃,这很可能是由于MapData
initWithCoordination
方法中的此代码造成的:

title = tl;
subtitle = s;
通过以这种方式初始化实例变量,MapData对象不会保留字符串。当您调用
[mapData release]
时,字符串将被解除分配,随后当地图视图尝试访问注释的标题和副标题时,它将崩溃

将初始化更改为:

title = [tl copy];
subtitle = [s copy];
并取消对
[mapData release]的评论


关于“在键值观察者仍然注册时解除分配…”警告消息,这可能是由于注释使用的坐标无效(请参阅)。对于每个注释,确保纬度在-90到90之间,经度在-180到180之间


关于“[MKUserLocation tag]:无法识别的选择器”崩溃,这与上述两个问题无关。发生此错误的原因是地图视图为所有注释调用了
viewForAnnotation
delegate方法,而不仅仅是您添加的注释。这意味着它也被称为地图视图本身创建的用户位置蓝点。该用户位置批注的类型为
MKUserLocation
,而自定义批注的类型为
MapData
。当地图视图为用户位置调用
viewForAnnotation
时,该代码崩溃,因为
MKUserLocation
类没有
标记
属性

处理此问题的最简单方法是在
viewForAnnotation
方法的顶部,检查注释的类型是否为
MKUserLocation
,并为视图返回
nil
(它告诉地图视图显示
title = [tl copy];
subtitle = [s copy];
- (MKAnnotationView *)mapView:(MKMapView *)mapView 
    viewForAnnotation:(id<MKAnnotation>)annotation
{
    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;  //show standard blue dot view for user location
if((annotation).tag == 2) annotationView.pinColor = MKPinAnnotationColorRed;
else annotationView.pinColor = MKPinAnnotationColorGreen;
if ([annotation isKindOfClass:[MapData class]])
{
    MapData *mapData = (MapData *)annotation;
    if (mapData.tag == 2)
        annotationView.pinColor = MKPinAnnotationColorRed;
    else
        annotationView.pinColor = MKPinAnnotationColorGreen;
}
Record *record = [[[Record alloc] init]autorelease];
record = [currentProject.recordArray objectAtIndex:i];
Record *record = [currentProject.recordArray objectAtIndex:i];
MapData *mapData =[[MapData alloc] initWithCoordinate:newCoordinate 
    withTag:tag withTitle:title withSubtitle:title];
if (annotationView == nil)
{
    annotationView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:record] autorelease];
}
else
{
    //We're re-using a view from another annotation
    //that's no longer on screen.
    //Update the view's annotation to the current one...
    annotationView.annotation = annotation;
}