I am trying to learn how to drop pins on a map in iOS 6. I have a code which compiles and runs but which obviously leaks memory -- but when I release (or autoRelease) the mapData object my app crashes. The error is
An instance 0x1b7ac0
of class AddressAnnotation
was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak
to stop here in the debugger.
There is an earlier post on just this error, also with respect to MapKit:
Setting breakpoint at NSKVODeallocateBreak
But it does not help me:
First, I don't really understand the answer, but also it seems the answer is not relevant to my problem because I am not setting an observer in any way (that I know of, that is!) For example, nowhere in my code do I have the lines
[addressAnnotation addObserver:self forKeyPath:kSelectedAnnotationObserverKeyPath options:NSKeyValueObservingOptionNew context:@"selectedOrDeselected"];
or anything else remotely similar, which were suggested to be the problem.
Having said that, I should also say I do not really understand the concept of the observer -- I have of course created a custom class MapData
, which is an NSObject <MKAnnotation>
and I suppose that this could also be a source of the problem. But I am basically plumb stupefied.
I have tried to set the suggested symbolic break point but it is not helpful to me: I see I have a BAD ACCESS
condition but that is all I really understand!
The code I have written is this:
- (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];
}
and then the next needed bit
- (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;
}
This code runs, so long as the mapData object is not released. But clearly I need to release it. As another clue, if I uncomment
// if((annotation).tag == 2) annotationView.pinColor = MKPinAnnotationColorRed;
// else annotationView.pinColor = MKPinAnnotationColorGreen;
I get another error:
[MKUserLocation tag]: unrecognized selector sent to instance 0x9fcb010 2013-05-22 23:05:13.726 Geo360[1175:c07] *** Terminating app due to uncaught exception
'NSInvalidArgumentException'
, reason: '-[MKUserLocation tag]:
unrecognized selector sent to instance0x9fcb010
'
but it seems to me that this second error is a simpler stupidity on my part that I at least know how to go about finding. But the error "class AddressAnnotation
" has me totally lost. Any help is greatly appreciated!
Edit:
Hi All -- Thank you for taking the time to help. I am still confused. Attached is the code for the MapData object as suggested by AnnaKarenina. Verbumdei suggested I put the array in ViewDidLoad method as a strong property -- I had played with that but I also want to be able to refresh the map pins with an array that may have more data or fewer data, so it seemed to me I needed to make the array anew each time. Perhaps not? AnnaKarenina suggested there may be a release problem in MapData and now that I look at it I am a bit suspicious that I am not releasing tag -- but on the other hand, doing so generates a warning!
Thank you again for helping... still not solved.
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
and 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