Reputation: 3319
I am working on a little project that shows 7 different types of annotations on the map. My annotations are taken from a url result in array and I parse it using JSON. I have lots of annotations and everything seems to look good once the map loads. After zooming in and zooming out, the the pin images changes for some reason to the wrong pin image (a specific image, no clue why).
I am sure I am missing something here...may you please help :) ?
Here's one part of my code, let me know if you need anymore of it:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString *identifier;
if(_mapView.tag==1){identifier = @"TurbulencePin";}
if(_mapView.tag==2){identifier = @"IcingPin";}
if(_mapView.tag==3){identifier = @"WindsPin";}
if(_mapView.tag==4){identifier = @"TemperaturePin";}
if(_mapView.tag==5){identifier = @"CloudsPin";}
if(_mapView.tag==6){identifier = @"VisibilityPin";}
if(_mapView.tag==7){identifier = @"MultiplePin";}
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
if ([annotation isKindOfClass:[Annotation class]]) {
CustomAnnotationView* annotationView = (CustomAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
annotationView = nil;
if (annotationView == nil) {
annotationView = [[CustomAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"%@.png",identifier]];
annotationView.image = img;
}
else
{
annotationView.annotation = annotation;
}
return annotationView;
}
return nil;
}
Update:
Based upon feedback of others, I've modified the code for the image setting to be as follows:
Annotation *myCustomAnn = (Annotation *)annotation;
NSString *imgName = myCustomAnn.imageName;
UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"%@Pin.png",imgName]];
annotationView.image = img;
return annotationView;
Plus, I removed the annotationView = nil;
However, I cannot set the image name in the annotation.m as a hardcoded value because I need to display a different pin image for each annotation. I'm sure that there is an explanation but the only value that I can get from the annotation.m under the mapView:viewForAnnotation: is the annotation coordinates (myCustomAnn.coordinate.latitude
and myCustomAnn.coordinate.longitude)
, I have no clue how to get other properties from the annotation.m
The other properties, such as title, imgname etc comes back as null
Upvotes: 5
Views: 7164
Reputation: 438162
One issue is that the viewForAnnotation
is determining the correct image to show based upon a class instance variable. Generally the identifier for the annotation's image would be a property of the custom annotation itself, not some external instance variable.
On top of that, it appeared that the annotation was being added to the map before all of the annotation's properties were being set. One should defer the addAnnotation
until all of the annotation's properties are set.
Alternatively, you can add the annotations to a NSMutableArray
, tweak them as you see fit, and only add the annotations at the very end using the addAnnotations
(note the s), passing it the array.
Upvotes: 0
Reputation: 3319
SOLVED by Rob
The problem was, that I could not retrive the annotation properties which I set at my VC. The reason was that I used the [_mapView addAnnotation:ann];
command, before I set all the annotation's properties. That said, by moving this line to the end part of the annotation initial properties setup, solved the problem.
Thank you all and big thanks to Rob! I'm up to my next challenge.
Upvotes: 0
Reputation:
The main problem is that the code in viewForAnnotation
is relying on the outside variable _mapView.tag
to determine the annotation view.
It is unsafe to assume when and how frequently the viewForAnnotation
delegate method will be called by the map.
If an annotation's view depends on certain values, it is generally best to embed those values directly in the annotation object itself. This way, in the viewForAnnotation
delegate method, you can reference those annotation-specific values through the annotation
parameter that is passed to the method. Those annotation-specific values should be set when creating the annotation (before calling addAnnotation
).
For some more details and examples, see:
A separate issue is the code is setting annotationView
to nil
after calling dequeueReusableAnnotationViewWithIdentifier
which defeats the dequeue.
At least in viewForAnnotation
, the corrected code where it handles the Annotation
class might look like this (not the whole method -- just the part inside the second if
):
static NSString *identifier = @"ann";
CustomAnnotationView* annotationView = (CustomAnnotationView*)[mapView
dequeueReusableAnnotationViewWithIdentifier:identifier];
//annotationView = nil; // <-- remove this line
if (annotationView == nil)
{
annotationView = [[CustomAnnotationView alloc]
initWithAnnotation:annotation
reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
}
else
{
annotationView.annotation = annotation;
}
//MOVE the setting of the image to AFTER the dequeue/create
//because the image property of the annotation view
//is based on the annotation and we can update image in one place
//after both the dequeue and create are done...
//Get the image name from the annotation ITSELF
//from a custom property (that you add/set)
Annotation *myCustomAnn = (Annotation *)annotation;
NSString *imgName = myCustomAnn.imageName;
//imageName is the custom property you added/set
UIImage *img = [UIImage imageNamed:
[NSString stringWithFormat:@"%@.png",imgName]];
annotationView.image = img;
return annotationView;
Upvotes: 5