Question

I'm trying to add a MKAnnotation with an icon to a map using this code for the annotation:

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
@interface MapItem : NSObject<MKAnnotation>
{
    CLLocationCoordinate2D coordinate;
}
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, assign) NSString *itemtitle;
@property (nonatomic, assign) NSString *icon;
@property (nonatomic, assign) NSString *itemsubtitle;

- (NSString *)subtitle;
- (NSString *)title;
@end

#import "MapItem.h"

@implementation MapItem
@synthesize coordinate;
@synthesize icon;
@synthesize itemtitle;
@synthesize itemsubtitle;
-(NSString*) title{
    return self.itemtitle;
}
-(NSString*) subtitle{
    return self.itemsubtitle;
}

@end

And this from the uiview:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
    static NSString *identifier = @"MapItem";
    if ([annotation isKindOfClass:[MapItem class]]) {

        MKAnnotationView *annotationView = (MKAnnotationView *) [_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
        if (annotationView == nil) {
            annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
            annotationView.enabled = YES;
            annotationView.canShowCallout = YES;

            annotationView.image = [UIImage imageNamed:((MapItem *)annotation).icon];



        } else {
            annotationView.annotation = annotation;
        }

        return annotationView;
    }

    return nil;
}

This code is working and I can see the annotations on the map only the app crashes the second I'm touching the map:

2014-03-25 14:53:30.540 PASIL[444:60b] -[__NSArrayM length]: unrecognized selector sent to instance 0x19f26230
2014-03-25 14:53:30.541 PASIL[444:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM length]: unrecognized selector sent to instance 0x19f26230'
*** First throw call stack:
(0x2dc59fd3 0x384d0ccf 0x2dc5d967 0x2dc5c253 0x2dbab7f8 0x2ee10e1f 0x2ee2a5c5 0x2ee2a943 0x304b081f 0x304b069b 0x304a51b3 0x304a4f9f 0x30478e2d 0x2dc2525b 0x2dc2472b 0x2dc22f1f 0x2db8df4f 0x2db8dd33 0x32ae6663 0x304d916d 0xea145 0x389ddab7)
libc++abi.dylib: terminating with uncaught exception of type NSException

Adding annotations:

  for (NSDictionary *dataDict in responseObject) {

            if([dataDict objectForKey:@"longitude"]!= (id)[NSNull null])
            {
                NSString *title=[dataDict objectForKey:@"title"];
                NSInteger report_type_id=[[dataDict objectForKey:@"report_type_id"] integerValue];
                float longitude=[[dataDict objectForKey:@"longitude"] floatValue];
                float latitude=[[dataDict objectForKey:@"latitude"] floatValue];
                CLLocationCoordinate2D coordinate;
                coordinate.latitude = latitude;
                coordinate.longitude = longitude;
                MapItem *annotation = [[MapItem alloc] init];
                annotation.coordinate=coordinate;
                annotation.itemtitle=title;
                switch(report_type_id)
                {
                    case 1:

                        annotation.itemsubtitle=@"Terror";
                        annotation.icon=@"map-legend-terrorism.png";
                        break;
                    case 2:

                        annotation.itemsubtitle=@"Traffic";
                        annotation.icon=@"map-legend-traffic.png";

                        break;
                    case 3:

                        annotation.itemsubtitle=@"Weather";
                        annotation.icon=@"map-legend-weather.png";
                        break;
                    case 4:

                        annotation.itemsubtitle=@"Crime";
                        annotation.icon=@"map-legend-crime.png";
                        break;

                }
                [self.mapView addAnnotation:annotation];
            }



        }
Was it helpful?

Solution

The problem is in how the NSString properties in the MapItem class are declared (not that one of the titles is an array as suggested in my comments):

@property (nonatomic, assign) NSString *itemtitle;
@property (nonatomic, assign) NSString *icon;
@property (nonatomic, assign) NSString *itemsubtitle;

By declaring the properties as assign, the values are not retained by the annotation object and the memory later (when the map view tries to access it) is pointing to something else (in your case it just happened to be something that looked like it was an array).

Change the declarations to this (change assign to copy):

@property (nonatomic, copy) NSString *itemtitle;
@property (nonatomic, copy) NSString *icon;
@property (nonatomic, copy) NSString *itemsubtitle;


A separate, unrelated issue you will encounter later is with annotation view re-use:
Right now, in viewForAnnotation, the image of the view is only being set when a view is created (when annotationView == nil) for some annotation "x".

However, if a view is re-used for another annotation "y", the image will still be set to the one when the view was originally created for annotation "x".

To fix this potential problem, move the image assignment to after the if-else block:

    //Don't assign the image here
    //(because it's specific to the current annotation)
    //annotationView.image = [UIImage imageNamed:((MapItem *)annotation).icon];
} else {
    annotationView.annotation = annotation;
}

//Assign the image here...
//(because it's specific to the current annotation)
annotationView.image = [UIImage imageNamed:((MapItem *)annotation).icon];

return annotationView;

OTHER TIPS

I use custom annotations on this application, it should be a good example for you.

Green Up Vermont App - MapViewController

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top