Displaying custom multiple pins shows wrong pins for locations - ios

This problem has been bugging me for a couple of weeks already!
I have a tab bar application. On one tab I am entering points, and on another tab, the points are displayed on a map. Pins should be different dependent on the types of points.
The problem that I face is that every time I switch from one tab to another, the pin images change from what they should be to other images. For example, if I have four points on the map, three displayed as a circle and one as a triangle, the triangle will be moving around from one point to another. Images seem to change quite randomly.
So, this is the code:
ViewController.m
-(void) viewWillAppear:(BOOL)animated
{
// Select the type of map
if (isMapSelected == NO) {
self.mapView.mapType = MKMapTypeSatellite;
}
else {
self.mapView.mapType = MKMapTypeStandard;
}
// Add region to the map (center and span)
[self addRegion];
// Removing old annotation
[self.mapView removeAnnotations:mapLocations];
// Initializing arrays for the annotations
mapLocations = [[NSMutableArray alloc]init];
[self addAnnotation];
}
-(void) addAnnotation
{
CLLocationCoordinate2D mapLocation;
IGAMapAnnotation *mapAnnotation;
// Calculate how many points are included
NSInteger numberOfPoints = [coordinatesTempArray count];
// Annotations will be added only of the flight plan includes at least one point
if (numberOfPoints > 0)
{
// Trying to add coordinates from the array of coordinates
for (NSInteger i=0; i < ([coordinatesTempArray count]); i++) {
mapAnnotation = [[IGAMapAnnotation alloc]init];
// Taking a point in the array and getting its coordinates
self.mapCoordinates = [coordinatesTempArray objectAtIndex:i];
// Getting a point in the array and getting its lattitude and longitude
self.mapLatitude = [[self.mapCoordinates objectAtIndex:0]doubleValue];
self.mapLongitude = [[self.mapCoordinates objectAtIndex:1]doubleValue];
// Assigning the point coordinates to the coordinates to be displayed on the map
mapLocation.latitude = self.mapLatitude;
mapLocation.longitude = self.mapLongitude;
// Adding coordinates and title to the map annotation
mapAnnotation.coordinate = mapLocation;
mapAnnotation.title = [navaidNamesTempArray objectAtIndex:i];
mapAnnotation.subtitle = nil;
mapAnnotation.navaidType = [navaidTypesTempArray objectAtIndex:i];
// Adding the annotation to the array that will be added to the map
[mapLocations addObject:mapAnnotation];
}
// Adding annotations to the map
[self.mapView addAnnotations:mapLocations];
}
}
-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if([annotation isKindOfClass:[IGAMapAnnotation class]])
{
IGAMapAnnotation *myLocation = (IGAMapAnnotation *) annotation;
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"IGAMapAnnotation"];
if (annotationView == nil)
annotationView = myLocation.annotationView;
else
annotationView.annotation = annotation;
return annotationView;
}
else
return nil;
}
IGAMapAnnotation.m
#synthesize coordinate = _coordinate;
#synthesize title = _title;
#synthesize subtitle = _subtitle;
#synthesize type = _type;
// Tried to have this init method but was never able to make it work. Without it, the program crashes too!!!!
-(id)initWithTitle:(NSString *)newTitle Type:(NSString *)type Location:(CLLocationCoordinate2D) newCoordinate
{
self = [super init];
if (self) {
_title = newTitle;
_coordinate = newCoordinate;
_type = type;
}
return self;
}
-(MKAnnotationView *) annotationView {
MKAnnotationView *annotationView = [[MKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:#"IGAMapAnnotation"];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if ([self.type isEqual: #"A"] || [self.type isEqual: #"B"] || [self.type isEqual: #"C"])
{
annotationView.image = [UIImage imageNamed:#"circle.png"];
}
else if ([self.type isEqual: #"D"])
{
annotationView.image = [UIImage imageNamed:#"triangle.png"];
}
else if ([self.type isEqual: #"E"])
{
annotationView.image = [UIImage imageNamed:#"square.png"];
}
else
{
annotationView.image = [UIImage imageNamed:#"oval.png"];
}
return annotationView;
}
#end
This is it. So far, the behaviour makes no sense to me.
Thanks for your help!

It sounds like an annotation view re-use issue.
When the annotations are re-displayed, they are re-using views with the images of previous annotations. The image property in the view is not being updated as it should be when it is re-used for another annotation.
In the viewForAnnotation delegate method, this code looks wrong:
MKAnnotationView *annotationView = [mapView dequeue...
if (annotationView == nil)
annotationView = myLocation.annotationView;
else
annotationView.annotation = annotation;
If the dequeue returns a view (ie. a previously-created view that may have been created for an annotation of a different type), its annotation property is updated but its image property is not updated.
The existing code only sets the image property when creating a new annotation view (when dequeue returns nil).
Right now, the annotation view creation and image-setting code is in the annotation model class IGAMapAnnotation. It would be better to create a custom MKAnnotationView class that automatically updates the image property whenever its annotation property is updated.
However, another alternative is to put all the logic in the viewForAnnotation delegate method itself (and remove the annotationView method from the IGAMapAnnotation class).
Example of the updated viewForAnnotation delegate method:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if (! [annotation isKindOfClass:[IGAMapAnnotation class]])
{
//return default view if annotation is NOT of type IGAMapAnnotation...
return nil;
}
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"IGAMapAnnotation"];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"IGAMapAnnotation"];
//these properties don't change per annotation
//so they can be set only when creating a new view...
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
else
{
annotationView.annotation = annotation;
}
//whether we are using a completely new view or a re-used view,
//set the view's image based on the current annotation...
IGAMapAnnotation *myLocation = (IGAMapAnnotation *) annotation;
if ([myLocation.type isEqual: #"A"] || [myLocation.type isEqual: #"B"] || [myLocation.type isEqual: #"C"])
{
annotationView.image = [UIImage imageNamed:#"circle.png"];
}
else if ([myLocation.type isEqual: #"D"])
{
annotationView.image = [UIImage imageNamed:#"triangle.png"];
}
else if ([myLocation.type isEqual: #"E"])
{
annotationView.image = [UIImage imageNamed:#"square.png"];
}
else
{
annotationView.image = [UIImage imageNamed:#"oval.png"];
}
return annotationView;
}

Related

Adding multiple annotations with multiple images on mapview in ios Objective-c?

I am working on an old application and need to make changes in Mapview. Previously we need to show multiple annotations on mapview with same images on each pin but now we have to show different images on annotation view pins to display address. I am using the following code to display annotation pins but it always shows the same image on annotation pins.
Here is my code:
- (MKAnnotationView *) mapView:(MKMapView *)mapView1 viewForAnnotation:(id <MKAnnotation>) annotation
{
NSLog(#"Eventtype Array is %#",eventTypeArray);
MKAnnotationView * pinView = nil;
if(annotation != _mapvw.userLocation)
{
static NSString * defaultPinID = #"pinId";
pinView = (MKAnnotationView *)[_mapvw dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
{
pinView = [[MKAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:defaultPinID];
}
for ( int i=0; i<[eventTypeArray count]; i++)
{
eventTypeStr = [NSString stringWithFormat:#"%#",
[eventTypeArray objectAtIndex:i]];
NSLog(#"Event Type is %#",eventTypeStr);
if ([eventTypeStr isEqualToString:#"0"])
{
NSLog(#"Eventtype Array is %#",eventTypeStr);
NSLog(#"Event Type is %#",eventTypeStr);
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"smiley.png"];
}
else if ([eventTypeStr isEqualToString:#"1"])
{
NSLog(#"Event Type is %#",eventTypeStr);
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"dollar1.png"];
}
else if ([eventTypeStr isEqualToString:#"2"])
{
NSLog(#"Event Type is %#",eventTypeStr);
pinView.canShowCallout = YES;
pinView.image = [UIImage imageNamed:#"donation.png"];
}
}
}
return pinView;
}
You’re iterating through your array of event types for every annotation, presumably always ending with the image associated for the last one in eventTypeArray.
Instead, you want the “event type” to be a property of the annotation. Then, when generating your annotation view, you can look at the annotation’s event type to know which image to use.
So, first, you haven’t done so already, you’d have an annotation that has an eventType property:
typedef NS_ENUM(NSUInteger, EventType) {
EventTypeSmiley,
EventTypeDollar,
EventTypeDonation,
};
#interface EventAnnotation: MKPointAnnotation
#property (nonatomic) EventType eventType;
#end
#implementation EventAnnotation
#end
Now, in this case, I’m using an enumeration for my event types, but you can use whatever type you want. (Even if you stick with the event type array, I’d still use an enumeration to excise cryptic 0/1/2 values sprinkled throughout your code.)
Then, when you add annotations to your map, use this new annotation type, not MKPointAnnotation:
EventAnnotation *eventAnnotation = [[EventAnnotation alloc] init];
eventAnnotation.coordinate = coordinate;
eventAnnotation.title = #"Fund raiser";
eventAnnotation.eventType = EventTypeDollar;
Now that all of your annotations are EventAnnotation, you can have your viewForAnnotation act accordingly:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
NSAssert([annotation isKindOfClass:[EventAnnotation class]], #"Was expecting event annotation”); // obviously, handle non-EventAnnotation annotations however you want, but I’m going to catch failures for now
static NSString *identifier = #"EventAnnotation";
MKAnnotationView *annotationView = [_mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!annotationView) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.canShowCallout = YES;
} else {
annotationView.annotation = annotation; // don't forget this line!
}
EventAnnotation *eventAnnotation = (EventAnnotation *)annotation;
switch (eventAnnotation.eventType) {
case EventTypeSmiley:
annotationView.image = [UIImage imageNamed:#"smiley.png"];
break;
case EventTypeDollar:
annotationView.image = [UIImage imageNamed:#"dollar1.png"];
break;
case EventTypeDonation:
annotationView.image = [UIImage imageNamed:#"donation.png"];
break;
}
return annotationView;
}

map view custom annotation view images not loading properly in device

i am using multiple annotation views with different images in my map view. Images are loading properly in simulator but not in device.i am not able to figure out the reason for this issue..following is my code
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString * const annotationIdentifier = #"CustomAnnotation";
annotationView1 = [mapUrCommView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
MKAnnotationView *annotationView2 = nil;
if (annotationView1)
{
annotationView1.annotation = annotation;
if(mapUrCommView.userInteractionEnabled)
annotationView1.image = [UIImage imageNamed:#"MapPinDarkBlue75#2x.png"];// map-pin-black.png
else
{
//if(annotationView1.annotation == self.currentAnnotation|| annotation == self.previousAnnotation)
NSLog(#"in annotation view 1");
annotationView1.image = [UIImage imageNamed:#"mapDrawPoint#2x.png"];// Bluedot.png
}
annotationView1.tag=111;
return annotationView1;
}
else
{
annotationView2 = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
annotationView2.image = [UIImage imageNamed:#"MapPinDarkBlue75#2x.png"];// map-pin-black.png
annotationView2.canShowCallout = YES;
return annotationView2;
}
return nil;
}
here i am drawing physical boundaries for a location in my app...so annotation view 1 is view which i am drawing presently & annoation view 2 will be having all annotations custom view images(all annotations will be having same images) which i already drawn in past..custom annotaion images are loading fine in simulator but not in device
It's worked me for using custom class for annotation.. Please refer this sample Apple documentation.
1.) Allocate MapAnnotation
mapAnnotation = [[MapAnnotation alloc]init];
2.) Set Coordinate for your lat and long
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake([[NBCGPSLocation sharedInstance].gpsLatitude doubleValue], [[NBCGPSLocation sharedInstance].gpsLongitude doubleValue]);
[mapAnnotation setCoordinate:coord];
[self.mapSDKView addAnnotation:mapAnnotation];
3.) Now this delegate method will call once you go that lat and long location
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[CustomAnnotation class]])
{
if(!customAnnotationView)
customAnnotationView = [[MKAnnotationView alloc]init];
customAnnotationView.image = [UIImage imageNamed:#"locationCustom"];
customAnnotationView.annotation = annotation;
return customAnnotationView;
}
else
{
if(!annotationView)
annotationView = [[MKAnnotationView alloc]init];
annotationView.image = [UIImage imageNamed:#"locationIcon"];
annotationView.annotation = annotation;
return annotationView;
}
}

iOS MapClustering: CCHMapClusterController: Problems when zooming out after zooming in. Single annotations show cluster-annotation callouts

I am trying out this new awesome library for annotation clustering called CCHMapClusterConroller.
I reckon there is little or no help to get here, since the library is so new, but I'll give it a shot.
I am having trouble with the annotation callouts and I do not know what I am doing wrong.
When I enter my view controllers view, the annotations are clustered perfectly.
When I then zoom in on my annotations they are declustered as expected.
However, when I zoom back out and the annotations starts to group up to clusters again, some clusters have the image of a single annotation. The same thing goes for their callouts. They have the titles and subtitles of my clustered annotations, but they have the disclosure button which i have only assigned to single, unclustered annotations.
This is how I initialize my cluster controller:
...
// viewDidLoad
self.mapClusterController = nil;
self.mapClusterController = [[CCHMapClusterController alloc] initWithMapView:self.mapView];
self.mapClusterController.delegate = self;
self.mapClusterController.cellSize = 25;
self.mapClusterController.marginFactor = 0.4;
//
...
This is how i populate the controller with my own custom annotations:
//...
[self.mapClusterController removeAnnotations:[self.mapClusterController.annotations allObjects] withCompletionHandler:nil];
NSMutableArray *arrayWithAnnotations = [[NSMutableArray alloc] init];
FFMapAnnotation *annotation;
for(FFPlace *place in self.searchResult){
annotation = [[FFMapAnnotation alloc] init];
annotation.title = place.placeName;
annotation.coordinate = CLLocationCoordinate2DMake(place.placeLatitude, place.placeLongitude);
annotation.place = place;
annotation.subtitle = place.placeAddress;
[arrayWithAnnotations addObject:annotation];
}
[self.mapClusterController addAnnotations:arrayWithAnnotations withCompletionHandler:nil];
//...
Now, I do believe that these two methods work correctly.
I imagine that the problem lies within the viewForAnnotation method.
This is currently how it looks:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *annotationView;
if ([annotation isKindOfClass:CCHMapClusterAnnotation.class]) {
static NSString *identifier = #"clusterAnnotation";
annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (annotationView) {
annotationView.annotation = annotation;
} else {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.canShowCallout = YES;
}
CCHMapClusterAnnotation *clusterAnnotation = (CCHMapClusterAnnotation *)annotation;
clusterAnnotation.delegate = self;
if(!clusterAnnotation.isCluster){
FFMapAnnotation *annot2 = (FFMapAnnotation*)clusterAnnotation.annotations.allObjects[0];
annotationView.image = [UIImage imageNamed:[DefinedCategories getCategoryInformationForID:annot2.place.placeMainCategoryID].mapImage];
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd];
annotationView.rightCalloutAccessoryView.tag = -1;
}else {
return nil;
}
}
return annotationView;
}
// the return nil at the end makes the annotation view a regular MKPinAnnotationView, which I use to visually represent my clusters.
Finally, the two delegate methods for cluster title and subtitle looks like this:
- (NSString *)mapClusterController:(CCHMapClusterController *)mapClusterController titleForMapClusterAnnotation:(CCHMapClusterAnnotation *)mapClusterAnnotation
{
NSString *title;
if(mapClusterAnnotation.annotations.count > 1){
title = [NSString stringWithFormat:#"%ld %#", (unsigned long) mapClusterAnnotation.annotations.count, [AppDelegate get:#"PLACES"alter:nil]];
} else{
FFMapAnnotation *annotation = mapClusterAnnotation.annotations.allObjects[0];
return annotation.title;
}
return title;
}
- (NSString *)mapClusterController:(CCHMapClusterController *)mapClusterController subtitleForMapClusterAnnotation:(CCHMapClusterAnnotation *)mapClusterAnnotation
{
NSString *title;
if(mapClusterAnnotation.annotations.count > 1){
title = [AppDelegate get:#"ZOOM_FURTHER"alter:nil];
} else{
FFMapAnnotation *annotation = mapClusterAnnotation.annotations.allObjects[0];
return annotation.subtitle;
}
return title;
}
What i want:
What is happening:
Am I missing something vital in the delegate methods? I spent all day debugging this.
EDIT:
Adding the delegate method
- (void)mapClusterController:(CCHMapClusterController *)mapClusterController willReuseMapClusterAnnotation:(CCHMapClusterAnnotation *)mapClusterAnnotation
{
MKAnnotationView *annotationView = [_mapView viewForAnnotation:mapClusterAnnotation];
if(!(mapClusterAnnotation.annotations.count == 1)){
annotationView.image = [UIImage imageNamed:#"map_icon_button_thing"];
annotationView.rightCalloutAccessoryView = nil;
}else {
FFMapAnnotation *annotation = mapClusterAnnotation.annotations.allObjects[0];
annotationView.image = [UIImage imageNamed:[DefinedCategories getCategoryInformationForID:annotation.place.placeMainCategoryID].mapImage];
}
}
solved my issues!

MKAnnotationView not displayed when object creation is performed within a custom annotation class

Environment
Xcode: 5.0.2, Device: iPhone,
iOS: iOS 7
I am trying to use the mapView:viewForAnnotation: delegate method. Within this method, if I create the MKAnnotationView object, the pin gets displayed without any issue. Here is the working code:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[CustomeAnnotation class]])
{
// CustomeAnnotation *myLocation = (CustomeAnnotation *)annotation;
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"MyCustomAnnotation"];
if (annotationView == nil)
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"MyCustomAnnotation"];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
//annotationView.image = [UIImage imageNamed:#"park_icon"];
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
// annotationView = myLocation.createAnnotationView;
else
annotationView.annotation = annotation;
//return nil;
return annotationView;
}
else
return nil;
}
When I create a class method and move the MKAnnotationView object creation and property setting within the class method and I call it from the mapView:viewForAnnotation: delegate method, the pin does not appear.
Here is the code for the two methods in question (mapView:viewForAnnotation: and createAnnotationView):
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.mapView.delegate = self;
CLLocationCoordinate2D baysideParkCoordinates = CLLocationCoordinate2DMake(25.774407, -80.185797);
CustomeAnnotation *baysideParkAnnotation = [[CustomeAnnotation alloc] initWithTitle:#" Bayfront Park"
coordinate:baysideParkCoordinates];
[self.mapView addAnnotation:baysideParkAnnotation];
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[CustomeAnnotation class]])
{
CustomeAnnotation *myLocation = (CustomeAnnotation *)annotation;
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:#"MyCustomAnnotation"];
if (annotationView == nil)
annotationView = [myLocation createAnnotationView];
else
annotationView.annotation = annotation;
// return nil;
return annotationView;
}
else
return nil;
}
#end
The custom class
#import "CustomeAnnotation.h"
#implementation CustomeAnnotation
-(id)initWithTitle:(NSString *)newTitle coordinate:(CLLocationCoordinate2D) newCoordinate
{
self = [super init];
if (self)
{
self.title = newTitle;
self.coordinate = newCoordinate;
}
return self;
}
-(MKAnnotationView *)createAnnotationView
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:self reuseIdentifier:#"MyCustomAnnotation"];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
//annotationView.image = [UIImage imageNamed:#"park_icon"];
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
#end
The import statement for the CustomeAnnotation class is included in the ViewController.h file.
At this point I believe I am not passing back correctly the MKAnnotationView object back to the method call in the ViewController implementation file. Could anyone tell me what is it that I am doing wrong on the second set of code?
In the second set of code, in createAnnotationView, the annotation is not showing because it's not setting the image.
Note that an MKAnnotationView does not have a default image so if you don't set it, the annotation is invisible.
Uncomment the setting of the image (or create an MKPinAnnotationView instead).
The reason the first set of code works (even though it is also creating an MKAnnotationView) is because there's actually a small bug in the code:
MKAnnotationView *annotationView = [mapView dequeue...
if (annotationView == nil)
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] init...
//^^^^^^^^^^^^^^^^ Here, the code declares a NEW, LOCAL variable
// named annotationView but it has no connection to the
// annotationView declared outside the if-block.
Because the annotationView declared outside the if is never set, it stays nil and that's what the delegate method actually returns.
When you return nil from viewForAnnotation, the map view creates a default view for you (a red pin for your annotations, a blue dot for the user location).
To fix the first set of code, don't declare a new, local variable. Just set the variable:
MKAnnotationView *annotationView = [mapView dequeue...
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] init...
and don't forget to set the image (or create an MKPinAnnotationView instead).

Setting Map Pin colour dynamically for iOS

I parse an xml that contains the string 0 ,1 and 2.
//For reference
0 = Green
1 = Red
2 = Purple
I have a class that confirms to the MKAnnotaion that contains the below variables that are properties.
CLLocationCoordinate2D coordinate;
NSString *title;
NSString *subtitle;
MKPinAnnotationColor pinColor;
This class is named MyAnnotation
Now in the viewDidLoad of the map view I run a for loop to iterate over the parsed data
like the below (locationArray holds this data and I pull out all the info just fine.
for (int i = 0; i < locationArray.count; i++) {
myAnnotation =[[MyAnnotation alloc] init];
NSString *thePointName = [[locationArray objectAtIndex:i]xmlName];
NSString *theAddress = [[locationArray objectAtIndex:i]xmlAddress];
NSString *latString = [[locationArray objectAtIndex:i]xmlLat];
NSString *lonString = [[locationArray objectAtIndex:i]xmlLon];
//This is the string that pulls out the mentioned 0, 1 or 2 strings which represent the colour of the pins poinType is retained as a string
pointType = [[locationArray objectAtIndex:i]xmlType];
double theLatitude = [latString doubleValue];
double theLongtitude = [lonString doubleValue];
userLocation.latitude=theLatitude;
userLocation.longitude=theLongtitude;
myAnnotation.coordinate=userLocation;
myAnnotation.title=[NSString stringWithFormat:#"%#", thePointName];
myAnnotation.subtitle=[NSString stringWithFormat:#"%#", theAddress];
//I log that the points are actually giving either of the colors and if so set MyAnnotation class to the pincolor
NSLog(#"Points Color %#", pointType);
if ([pointType isEqualToString:#"0"]){
myAnnotation.pinColor = MKPinAnnotationColorGreen;
}else if ([pointType isEqualToString:#"1"]){
myAnnotation.pinColor = MKPinAnnotationColorRed;
}else if ([pointType isEqualToString:#"2"]) {
myAnnotation.pinColor = MKPinAnnotationColorPurple;
}
[mapView addAnnotation:myAnnotation];
}
Now in the MKAnnotationView view i do the below
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
// if it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// try to dequeue an existing pin view first
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView* pinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
pinView.animatesDrop=YES;
pinView.canShowCallout=YES;
//set pin color to the correct colour
if (myAnnotation.pinColor = MKPinAnnotationColorGreen) {
pinView.pinColor = MKPinAnnotationColorGreen;
}
else if (myAnnotation.pinColor = MKPinAnnotationColorRed) {
pinView.pinColor = MKPinAnnotationColorRed;
}
else if (myAnnotation.pinColor = MKPinAnnotationColorPurple){
pinView.pinColor = MKPinAnnotationColorPurple;
}
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = rightButton;
UIImageView *profileIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Profile.png"]];
pinView.leftCalloutAccessoryView = profileIconView;
return pinView;
}
I have also tried in the above method however it is not setting the pin colours. Everything else is fine!
//set pin color to the correct colour
if (pointType isEqualToString:#"0") {
pinView.pinColor = MKPinAnnotationColorGreen;
}
else if (pointType isEqualToString:#"1") {
pinView.pinColor = MKPinAnnotationColorRed;
}
else if (pointType isEqualToString:#"2"){
pinView.pinColor = MKPinAnnotationColorPurple;
}
This code in viewForAnnotation:
if (myAnnotation.pinColor = MKPinAnnotationColorGreen) {
will not work for two reasons:
It is using a single equals sign which is for assignment -- not for checking equality. It needs to use two equal signs to check for equality. However, this doesn't fix the main issue which is reason #2...
The code is checking the value of myAnnotation which is a variable set outside this delegate method. There is no guarantee that the delegate method will be called in sync with the for-loop in which myAnnotation is set. Do not assume that viewForAnnotation will be called right after you call addAnnotation. It is even possible for the delegate method to be called multiple times for the same annotation if the map view needs to display the annotation again after a zoom or pan.
Instead, you must use the annotation parameter that is passed to the delegate method. This is a reference to the annotation the map view wants a view for in the current call of the delegate method.
Since the annotation parameter is typed generically as id<MKAnnotation>, you'll first have to cast it to your custom class and then you can access any custom properties:
//first make sure this annotation is our custom class before casting it...
if ([annotation isKindOfClass:[MyAnnotation class]])
{
MyAnnotation *currentAnn = (MyAnnotation *)annotation;
if (currentAnn.pinColor == MKPinAnnotationColorGreen) {
pinView.pinColor = MKPinAnnotationColorGreen;
}
else if (currentAnn.pinColor == MKPinAnnotationColorRed) {
pinView.pinColor = MKPinAnnotationColorRed;
}
else if (currentAnn.pinColor == MKPinAnnotationColorPurple) {
pinView.pinColor = MKPinAnnotationColorPurple;
}
}
or even simpler:
//first make sure this annotation is our custom class before casting it...
if ([annotation isKindOfClass:[MyAnnotation class]])
{
MyAnnotation *currentAnn = (MyAnnotation *)annotation;
pinView.pinColor = currentAnn.pinColor;
}
(Unrelated, but why is the code setting the title of rightButton even though it won't be visible?)

Resources