I have a map on which I want to display both custom annotations with images and one default looking annotation with a red pin.
I've made my view into a map delegate in order to load the custom images, but what happens is that the default looking pin I want is not showing (since I don't load an image for it).
I'm adding a shortened version of my code below (with remarks).
How can I load an image for this pin? Is there a standard way to access the pin UIImage, or should I make the annotation somehow?
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *SFAnnotationIdentifier = #"SFAnnotationIdentifier";
MKPinAnnotationView *pinView =
(MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:SFAnnotationIdentifier];
MKPointAnnotation* pointAnnotation = (MKPointAnnotation*)annotation;
if (!pinView)
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:SFAnnotationIdentifier];
for (id location in self.locations) {
// if this is a "special" point loaded
if () {
UIImage *image = ; // get custom image from somewhere
annotationView.image = image;
return annotationView;
}
}
// if the code made here, I want the pin to be regular
return annotationView;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
OK, solved it.
return nil;
does the trick and gives the default view.
Change
UIImage *image = ; // get custom image from somewhere
to
UIImage *image = [UIImage imageNamed:#"YourPin.png"]; // get custom image from somewhere
And maybe you need to change the offset of annotationView
annotationView.centerOffset = CGPointMake( 0, annotationView.centerOffset.y - annotationView.image.size.height/2 );
Related
After uploading a custom image for the MKPinAnnotationView, I noticed that the pin was off-centered. The pin is supposed to be on a point on the route's polyline, and in the center of an mkcircle; however, the pin seems to be to the right of the polyline and a little north of the center. I tried experimenting with the centerOffset property, but when I plug values into the property, nothing seems to change. Here is the code,
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
static NSString *viewID = #"MKPinAnnotationView";
MKPinAnnotationView *annotationView = (MKPinAnnotationView*)
[self.mapView dequeueReusableAnnotationViewWithIdentifier:viewID];
if(annotationView ==nil){
annotationView = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:viewID];
}
annotationView.image = [UIImage imageNamed:#"Pin.png"];
annotationView.enabled = YES;
//doesn't move the pin, still offcentered
annotationView.centerOffset = CGPointMake(0,-50);
return annotationView;
}
Just something to add, I also noticed that with the new pin image, nothing pops up when I click on the pin. Before, with the default pin, a bubble of text would appear after clicking on the pin. Since this is the case, I want to include the code for the method that makes and places the pin on the map,
-(void) createAndAddAnnotationForCoordinate : (CLLocationCoordinate2D)coordinate{
MKPointAnnotation* annotation = [[MKPointAnnotation alloc]init];
annotation.coordinate = coordinate;
annotation.title = #"This is a pin!";
[mapView addAnnotation:annotation];
}
I also tried changing the pin image to see if that would influence the positioning of the MKPinAnnotationView. Although I was able to center the pin by editing the image, it isn't centered for other polylines. Any help would be appreciated!
First, an important point is that when using a custom annotation image, it's best to use the plain MKAnnotationView class instead of its subclass MKPinAnnotationView which is designed to automatically display a standard pin image.
This is because MKPinAnnotationView includes some built-in adjustments of the annotation view's frame and centerOffset based on its own pin image. In some cases, your custom image will even be replaced on the screen with the default pin image. So even though MKPinAnnotationView has an image property, the class will not always use it as expected.
Second, set the centerOffset such that as the map is zoomed, the part of the image that "points" to the coordinate keeps pointing to the coordinate. This is because the centerOffset is in screen CGPoints and does not scale with the zoom level of the map. If the centerOffset is not set properly, the "point" of the image will start to drift from the target coordinate.
Also note you may not even need to set centerOffset since the default will put the center of the image at the coordinate which you may be ok with.
Based on the image you posted, here is the code and resulting appearance without setting centerOffset (leaving it at the default):
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
static NSString *viewID = #"MKPinAnnotationView";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:viewID];
if (annotationView ==nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:viewID];
annotationView.image = [UIImage imageNamed:#"Pin.png"];
annotationView.canShowCallout = YES;
}
else {
annotationView.annotation = annotation;
}
return annotationView;
}
(I added the red center lines to show where the target coordinate is relative to the pin image.)
Here is the code and resulting appearance with centerOffset set so that the bottom points to the coordinate:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
static NSString *viewID = #"MKPinAnnotationView";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:viewID];
if (annotationView ==nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:viewID];
annotationView.image = [UIImage imageNamed:#"Pin.png"];
annotationView.canShowCallout = YES;
annotationView.centerOffset = CGPointMake(0,-15);
}
else {
annotationView.annotation = annotation;
}
return annotationView;
}
You have to set MKCoordinateRegion to load the map, edit your createAndAddAnnotationForCoordinate method as below
-(void) createAndAddAnnotationForCoordinate : (CLLocationCoordinate2D)coordinate{
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(coordinate, 3000, 3000); //Set zooming level
MKCoordinateRegion adjustedRegion = [mapView regionThatFits:viewRegion]; //add location to map
[mapView setRegion:adjustedRegion animated:YES]; // create animation zooming
MKPointAnnotation* annotation = [[MKPointAnnotation alloc]init];
annotation.coordinate = coordinate;
annotation.title = #"This is a pin!";
[mapView addAnnotation:annotation];
}
I have several MKPolygons for which I am using rendererForOverlay method override. Now inside each such polygons I need my annotation view to display.
I observe that the annotation view positions are quite inaccurate. Only when I zoom fully to the MKPolygon do I see the annotation view centered inside that MKPolygon.
I tried setting center of the MKAnnotationView derived class instance, but to no avail.
I tried playing with centerOffset property but to no avail. I am not sure what values I could pass to it to make the whole thing centered inside MKPolygon.
I am using my own MKAnnotationView derived subclass, not built in iOS MKPinAnnotationView or such.. Here is my viewforAnnotation implementation:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
{
//show default blue dot for user location...
return nil;
}
static NSString *reuseId = #"MapAnnotationID";
MWAnnotationView *av = (MWAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (av == nil)
{
av = [[MWAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
av.canShowCallout = NO;
//note that this my custom UIView derived class to show UI.
MWMapAnnotationView * mapAnnView = [[[NSBundle mainBundle] loadNibNamed:#"MapAnnotationView" owner:nil options:nil] firstObject];
mapAnnView.tag = TAG_ANNOTATION;
[av addSubview:mapAnnView];
av.centerOffset = CGPointMake(0, -15);
}
else
{
av.annotation = annotation;
}
if (map.region.span.longitudeDelta > MAX_LONGITUDEDELTA / 4)
{
av.hidden = YES;
}
else
{
av.hidden = NO;
}
//custom UI elements of my subview
mapAnnView.labelCapital.text = capital;
mapAnnView.labelPopulation.text = population;
if (imageName)
{
mapAnnView.imageAnnotation.image = [UIImage imageNamed:imageName];
}
else
{
mapAnnView.imageAnnotation.image = nil;
}
return av;
}
UPDATE:
It turns out setting centerOffset has no effect. Tried setting it at different points inside viewForAnnotation but to no avail. For anyone who is wondering, I have my own MKAnnotationView subclass where I have overridden centerOffset setter. Tested with iOS simulator version 8.0.
I am trying to rotate an image that is added to MKMapView as an annotation.
This is the code:
-(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"];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
}
else
{
annotationView.annotation = annotation;
}
IGAMapAnnotation *myLocation = (IGAMapAnnotation *) annotation;
// THIS IS IT!
if ([myLocation.type isEqual: #"PLANE"]) {
UIImage *planeImage = [UIImage imageNamed:#"planetracked.png"];
UIImageView *planeImageView = [[UIImageView alloc]initWithImage:planeImage];
planeImageView.transform = CGAffineTransformMakeRotation(M_PI_2);
annotationView.image = planeImageView;
}
return annotationView;
}
It obviously gives me an error as annotationView.image should assign an image and not UIImageView. I have tried various methods rotating just an image, for example this:
- (UIImage *)rotateImage:(UIImage *)image onDegrees:(NSString *)heading {
double angle = [heading doubleValue];
CGSize s = {image.size.width, image.size.height};
UIGraphicsBeginImageContext(s);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, 0,image.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextRotateCTM(ctx, 2*M_PI*angle/360);
CGContextDrawImage(ctx,CGRectMake(0,0,image.size.width, image.size.height),image.CGImage);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
They do not work either -- no image appears on the map.
Anyone knows how to rotate an annotation image on MKMapView?
Million thanks!
Instead of:
annotationView.image = planeImageView;
which is definitely wrong (the image property is a UIImage while planeImageView is a UIImageView), use addSubview: to add the UIImageView to the annotation view (leaving the view's image property nil and unused).
However, you'll also need to make some other adjustments so that:
The image is centered exactly on the coordinate (instead of its corner), and
Tapping anywhere on the image brings up the callout (instead of only one specific corner)
To do these things, increase the frame sizes of both views to account for the maximum width possible from a rotation (which is the square root of 2 times the original width assuming image is a square) and set the image view's contentMode to "center" so the image is not distorted by these frame size changes.
The other big issue is that if you have IGAMapAnnotations whose type is not "PLANE", they will either be:
Invisible if a new annotation view is created (because image is not set nor is any subview added to the annotation view), or,
Showing a "plane" image with the heading of some other annotation because the annotation view was dequeued (and is being re-used for another annotation).
To avoid the two types of annotations ("plane"/"not plane") from re-using each other's views, I suggest using a different re-use identifier for each type (not each annotation) and apply type-specific changes to the view.
The revised viewForAnnotation method would look like this:
-(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;
}
IGAMapAnnotation *myLocation = (IGAMapAnnotation *)annotation;
BOOL typeIsPlane = [myLocation.type isEqualToString:#"PLANE"];
int planeImageViewTag = 42;
NSString *reuseId = typeIsPlane ? #"IGAMapAnnotationPlane" : #"IGAMapAnnotationOther";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if (typeIsPlane)
{
//Here, just add the image view to the annotation view with no
//rotation. Only want to add the image view to the annotation
//view ONCE when the annotation view is initially created. If
//view is dequeued, it will already have an image view and we
//just update its rotation.
UIImage *planeImage = [UIImage imageNamed:#"planetracked.png"];
UIImageView *planeImageView = [[UIImageView alloc] initWithImage:planeImage];
planeImageView.tag = planeImageViewTag;
planeImageView.contentMode = UIViewContentModeCenter;
[annotationView addSubview: planeImageView];
CGRect avFrame = annotationView.frame;
//"1.5" on next line is the square root of 2 rounded up a bit.
avFrame.size = CGSizeMake(planeImage.size.width*1.5,
planeImage.size.height*1.5);
annotationView.frame = avFrame;
planeImageView.frame = annotationView.frame;
}
else
{
//If this IGAMapAnnotation is not a "plane",
//show some other default image.
//(Or, you could return nil to show a default red pin.)
annotationView.image = [UIImage imageNamed:#"NotAPlane.png"];
//May or may not need to set centerOffset.
//Either remove or adjust 0,0 as needed to
//center the image on the coordinates.
annotationView.centerOffset = CGPointMake(0, 0);
}
}
else
{
annotationView.annotation = annotation;
}
//At this point, we have a new or dequeued annotation view ready
//and pointing to the current annotation.
//Now make any annotation-specific changes to the view...
if (typeIsPlane)
{
UIImageView *planeImageView = (UIImageView *)[annotationView viewWithTag:planeImageViewTag];
planeImageView.transform = CGAffineTransformMakeRotation(M_PI_2);
//Replace M_PI_2 with rotation specific to this annotation's heading.
}
return annotationView;
}
By the way, use isEqualToString: instead of isEqual: with NSStrings.
For the removeAnnotations: problem, it must be that mapLocations contains new instances of the annotations on the map. To remove existing annotations, you have to provide a reference to the exact same objects that were added originally.
If you are always removing all annotations and re-adding all annotations, you can just do [self.mapView removeAnnotations:self.mapView.annotations];.
If you are only removing some annotations, you'll need to keep references to the ones originally added or iterate through the map view's annotations array and identify which ones should be deleted (keep a temporary NSMutableArray as the list of "annotations to remove") and then call removeAnnotations: with that list of annotations to remove.
The following seems to work. Million thanks to Anna without whom it would not have!
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if (! [annotation isKindOfClass:[IGAMapAnnotation class]]) {
return nil;
}
IGAMapAnnotation *myLocation = (IGAMapAnnotation *) annotation;
BOOL typeIsPlane = [myLocation.navaidType isEqualToString:#"PLANE"];
BOOL typeIsOne = [myLocation.navaidType isEqualToString:#"ONE"];
BOOL typeIsTwo = [myLocation.navaidType isEqualToString:#"TWO"];
BOOL typeIsThree = [myLocation.navaidType isEqualToString:#"THREE"];
int planeImageViewTag = 42;
NSString *reuseId;
if (typeIsPlane)
reuseId = #"IGAMapAnnotationPlane";
else if (typeIsOne)
reuseId = #"IGAMapAnnotationOne";
else if (typeIsTwo)
reuseId = #"IGAMapAnnotationTwo";
else if (typeIsThree)
reuseId = #"IGAMapAnnotationThree";
else
reuseId = #"IGAMapAnnotationOther";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (annotationView == nil)
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if (typeIsPlane)
{
UIImage *planeImage = [UIImage imageNamed:#"mapPLANE.png"];
UIImageView *planeImageView = [[UIImageView alloc] initWithImage:planeImage];
planeImageView.tag = planeImageViewTag;
planeImageView.contentMode = UIViewContentModeCenter;
[annotationView addSubview: planeImageView];
CGRect avFrame = annotationView.frame;
//"1.5" on next line is the square root of 2 rounded up a bit.
avFrame.size = CGSizeMake(planeImage.size.width*1.5,
planeImage.size.height*1.5);
annotationView.frame = avFrame;
planeImageView.frame = annotationView.frame;
}
else if (typeIsOne)
{
annotationView.image = [UIImage imageNamed:#"one.png"];
annotationView.centerOffset = CGPointMake(0, 0);
}
else if (typeIsTwo)
{
annotationView.image = [UIImage imageNamed:#"two.png"];
annotationView.centerOffset = CGPointMake(0, 0);
}
else if (typeIsThree)
{
annotationView.image = [UIImage imageNamed:#"three.png"];
annotationView.centerOffset = CGPointMake(0, 0);
}
else
return nil;
}
else
{
annotationView.annotation = annotation;
}
if (typeIsPlane)
{
// Convert current heading string to double
double headingDouble = [currentHeading doubleValue];
UIImageView *planeImageView = (UIImageView *)[annotationView viewWithTag:planeImageViewTag];
planeImageView.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(headingDouble));
}
return annotationView;
}
Im working on a mapview but Its not showing the user location like I want and also the Pins, I dont know if the code is correct, I think it is, so I need your help.
Heres the code for showing the location with a zoom:
- (void)viewDidLoad
{
self.MapView.showsUserLocation = YES;
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
coordinateuser.latitude = self.MapView.userLocation.coordinate.latitude;
coordinateuser.longitude = self.MapView.userLocation.coordinate.longitude;
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coordinateuser, 1200, 1200);
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self.MapView setRegion:region animated:YES];
});
[super viewDidLoad];
}
And heres the code for displaying a MKPinAnnotationView, this is the one that I think is wrong:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
static NSString *SFAnnotationIdentifier = #"SFAnnotationIdentifier";
MKPinAnnotationView *pinView =
(MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:SFAnnotationIdentifier];
if (!pinView)
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:SFAnnotationIdentifier];
return annotationView;
}
else
{
pinView.annotation = annotation;
}
cmtlocation = CLLocationCoordinate2DMake(19.502519,-99.259779);
//UIImage *flagImage = [UIImage imageNamed:#"flag.png"];
//annotationView.image = flagImage;
[annotation setCoordinate:cmtlocation];
return pinView;
}
So I will appreciate your help! Thanks!
Actually, it's the other way around than what the other answer says:
If the dequeue returns nil, code is creating an empty MKAnnotationView.
MKAnnotationView is empty by default so the annotations (including the user location) are invisible. At the top of viewForAnnotation, check if annotation is of type MKUserLocation and return nil. For other annotations, create an MKAnnotationView if you want to use a custom image. Otherwise, create (alloc+init) an MKPinAnnotationView which automatically provides a pin image.
Additionally...
You are not even calling addAnnotation for your custom annotation. You should not be setting the annotation's coordinate in the viewForAnnotation method. Instead, you should be creating an annotation object (eg. in viewDidLoad), setting its coordinate and title and then calling addAnnotation.
Also, in viewDidLoad, you are trying to access the user location coordinates immediately after setting showsUserLocation to YES. The user location will not be available immediately. Instead, move the setRegion call to the didUpdateUserLocation delegate method (or just set userTrackingMode to MKUserTrackingModeFollow).
I think your code is wrong, as you expected: If
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:SFAnnotationIdentifier];
does not return nil, you return just another annotation view:
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:SFAnnotationIdentifier];
return annotationView;
Otherwise, you try to set a property of a nil object:
pinView.annotation = annotation;
and then do something else before returning nil:
cmtlocation = CLLocationCoordinate2DMake(19.502519,-99.259779);
//UIImage *flagImage = [UIImage imageNamed:#"flag.png"];
//annotationView.image = flagImage;
[annotation setCoordinate:cmtlocation];
return pinView;
I am making an App in xCode with an MKMapView and MKAnnotations. If you make more than two annotations the extra waypoints colors (PinAnnotations) should be changed to purple.
Therefore I need something like a tag, IndexPath or ID from the annotation to identify the MKAnnotation in the MKAnnotation functions. I used this line of code:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
MKPinAnnotationView *pinView = nil;
if (annotation != mkMap.userLocation)
{
static NSString *defaultPinID = #"aPin";
pinView = (MKPinAnnotationView *)[mkMap dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if (pinView == nil)
{
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID];
pinView.canShowCallout = YES;
pinView.tag = mapView.annotations.count; // tag is not available for annotation in this function
}
}
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
pinView.draggable = YES;
if ([annotation isKindOfClass:[MKUserLocation class]])
return pinView;
NSLog(#"Annotation-Index: %d", [mapView.annotations indexOfObject:annotation]);
NSLog(#"MapView.annotations.count = %d", mapView.annotations.count);
if (1 == [mapView.annotations indexOfObject:annotation])
pinView.pinColor = MKPinAnnotationColorGreen;
else if (1 < [mapView.annotations indexOfObject:annotation])
{
pinView.pinColor = MKPinAnnotationColorRed;
// checkes for extra waypoints
if (2 < mapView.annotations.count)
{
for (int i = 2; i > mapView.annotations.count; i++)
{
MKPinAnnotationView *aView = [mapView.annotations objectAtIndex:i];
aView.pinColor = MKPinAnnotationColorPurple;
[mapView removeAnnotation:mapView.annotations[i]];
NSMutableArray *a = [[NSMutableArray alloc] init];
[a replaceObjectAtIndex:i withObject:aView];
[mapView addAnnotations:a];
}
}
}
return pinView;
}
I already google this question and found a number of solutions like I did
int AnnotationIndex = [mapView.annotations indexOfObject:annotation];
but the the output of this function (Annotation-Index) strikes my mind. Sometimes everything is fine but and the Annotation-Index has the right value but most of the time the values seems to be generated randomly and the scale goes from 0 up to 10 also if the MapView.annotations.count is just 3!
Best regards and thanks!
The recommended way of handling this is to make your own class that implements the MKAnnotation protocol and has a property that you can check during viewForAnnotations to see what colour to use. The annotations array from MKMapView is not guaranteed to be in the order in which you add annotations to the map. You may add annoy, annoy and then annoy but you may get back [anno2, anno3, anno1]. That's just the way it is and you can't change that. So, you could keep your own array of annotations that won't get rearranged. Or use the extra property idea if that will suit.
One thing you should not do is add more annotations during the viewForAnnotation function, that's really messed up.