iOS Pin color issue in mapkit

2019-09-04 12:21发布

I want my annotations in two colors. For that I have used following code,

- (MKAnnotationView *)mapView:(MKMapView *)sender viewForAnnotation:(id <MKAnnotation>)annotation {  
    static NSString *identifier = @"MyLocation";
    if ([annotation isKindOfClass:[PlaceMark class]]) {
        MKPinAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
        annotationView.enabled = YES;
        annotationView.canShowCallout = YES;
        @try {
            if (annotationView == nil) {
                annotationView = [[MKPinAnnotationView alloc]
                                  initWithAnnotation:annotation
                                  reuseIdentifier:identifier];
            } else {
                annotationView.annotation = annotation;
                
                if([[nsCenterOrOffice objectAtIndex:z] isEqualToString:@"C"])
                {
                    annotationView.pinColor = MKPinAnnotationColorRed;
                }
                else 
                {
                    annotationView.pinColor = MKPinAnnotationColorGreen;
                }
            }
        }
        @catch (NSException *exception) {
            NSLog(@"nsCenterOrOffice exception = %@",exception);
        }
        return annotationView;
    }
    return nil;
}

But still I am not able to set desired color for desired annotation. Sometimes particular annotation pin color is red and sometimes it's green. I am not getting why this is happening. Can anybody help me ? Thanks...

I rework on my code..this is my updated code

MapAnnotation.h

    #import <MapKit/MapKit.h>
    #import <Foundation/Foundation.h>

    @interface MapAnnotation : MKPointAnnotation
    {
        NSString *title;
        NSString *subtitle;
        int dealLnk;
        float latitude;
        float longitude;
        
        CLLocationCoordinate2D coordinate;
    }

    @property (nonatomic, copy) NSString *title;
    @property (nonatomic, copy) NSString *subtitle;
    @property (nonatomic, assign) int dealLnk;
    @property (nonatomic, assign) float latitude;
    @property (nonatomic, assign) float longitude;
    @property (nonatomic, readonly) CLLocationCoordinate2D coordinate;

    - (id)initWithTitle:(NSString *)ttl subTitle:(NSString *)subttl dealLink:(int)dealLnk latitude:(float)latitude longitude:(float)longitude andCoordinate:(CLLocationCoordinate2D)c2d;
@end

MapAnnotation.m

#import "MapAnnotation.h"

@implementation MapAnnotation

@synthesize title,subtitle,dealLnk,coordinate,latitude,longitude;

- (id)initWithTitle:(NSString *)ttl subTitle:(NSString *)subttl dealLink:(int)z latitude:(float)latitude1 longitude:(float)longitude1 andCoordinate:(CLLocationCoordinate2D)c2d {
    title = ttl;
    subtitle = subttl;
    dealLnk =z;
    coordinate = c2d;
    longitude = longitude1;
    latitude = latitude1;
    
    return self;
}
@end

And this is my implementation file

-(void)startAddingAnnotation
{
    @try {
        CLLocationCoordinate2D annotationCoord;
        
        z=0;
        for (int i=0; i < [nslatitude count] ; i++,z++)
        {
            
            MapAnnotation  *dealAnnotation   = [[MapAnnotation  alloc] init];
            
            dealAnnotation.dealLnk = z;
            annotationCoord.latitude =  (CGFloat) [[nslatitude objectAtIndex:i] floatValue];
            annotationCoord.longitude = (CGFloat)[[nslongitude objectAtIndex:i] floatValue];
            dealAnnotation.coordinate = annotationCoord;
            
            dealAnnotation.title = [nsCenterName objectAtIndex:i];
            dealAnnotation.subtitle = [nsCenterAddress objectAtIndex:i];
            
            NSLog(@"latitude = %f",dealAnnotation.latitude);
            NSLog(@"longitude = %f",dealAnnotation.longitude);
            
            NSLog(@"dealAnnotation.dealLnk = %d",dealAnnotation.dealLnk);
            NSLog(@"dz = %d",z);
            [mapView addAnnotation:dealAnnotation];
           
        }
        
    }
    @catch (NSException *exception) {
        
        NSLog(@"Exception = %@",exception);
    }
    
    cord.longitude = -112.05186;
    cord.latitude = 33.46577;
    
    MKCoordinateRegion region;
    region.center = cord;
    
    MKCoordinateSpan span = {.latitudeDelta = 1.0, .longitudeDelta = 1.0};
    region.span = span;
    
    [mapView setRegion:region];
    
    
}

#pragma mark - MapView_Delegate
- (MKAnnotationView *)mapView:(MKMapView *)sender viewForAnnotation:(id <MKAnnotation>)annotation {
    

    MapAnnotation *annotation1 = (MapAnnotation *)annotation;
    z = annotation1.dealLnk;
    
      NSLog(@"annotation1.longitude = %f",annotation1.latitude);
      NSLog(@"annotation1.longitude = %f",annotation1.longitude);
    
    if(z<[nslatitude count])
    {
        MKAnnotationView *pinView = nil;
        static NSString *defaultPinID = @"pin1";
        
        pinView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
        
      
        if ( pinView == nil )
            pinView = [[MKAnnotationView alloc]
                       initWithAnnotation:annotation1 reuseIdentifier:defaultPinID];
        pinView.canShowCallout = YES;
        
        @try {
            
            if([[nsCenterOrOffice objectAtIndex:z] isEqualToString:@"C"])
            {
                pinView.image = [UIImage imageNamed:@"flag1.png"];
            }
            else
            {
                pinView.image = [UIImage imageNamed:@"flag2.png"];
            }
            pinView.annotation = annotation1;
            pinView.tag = [[nsCenterName objectAtIndex:z] intValue];
            
        }
        @catch (NSException *exception) {
            NSLog(@"nsCenterOrOffice exception = %@",exception);
        }
        
        UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
        [rightButton setTitle:annotation.title forState:UIControlStateNormal];
        [pinView setRightCalloutAccessoryView:rightButton];

        return pinView;
    }
    else
    {
        return nil;
    }
    
}

Now the problem is, all the annotations are pointing some different location. I am not getting why this is happening? Is der anything wrong in my code?

2条回答
等我变得足够好
2楼-- · 2019-09-04 12:33

Your viewForAnnotation is relying upon some external variables, nsCenterOrOffice and z. We certainly can't help you until you show us how you're setting those variables.

Regardless, this is not a prudent practice. Your viewForAnnotation generally should rely solely upon properties of the annotation, not external variables.

查看更多
Root(大扎)
3楼-- · 2019-09-04 12:40

The condition that determines the pin color is based on data outside of this delegate method and there is no guarantee that it will be in sync with when this delegate method is called for a particular annotation.


In this if condition:

if([[nsCenterOrOffice objectAtIndex:z] isEqualToString:@"C"])

the z variable is apparently some instance variable declared and set (probably right before adding an annotation) outside this delegate method.

Again, there is no guarantee that the viewForAnnotation delegate method will be called immediately after an annotation is added. There is also no guarantee that the delegate method will be called only once for each annotation. So it's possible that the z value does not correspond to the current annotation that the delegate method is being called for.

It is very possible for the delegate method to be called well after addAnnotation is called, that it will be called in a different order than the annotations were added, and that it will be called multiple times for each annotation (eg. if user pans or zooms the map and annotations come back into view).


To fix this, add the "is center or office" property to the Placemark class itself and set that property when creating the annotation and before calling addAnnotation. Then, in the viewForAnnotation method, you can cast the annotation parameter as a Placemark and access the property to implement the condition. For example:

//where you create and add the annotation:
Placemark *pm = [[Placemark alloc...
pm.coordinate = ...
pm.title = ...
pm.centerOrOffice = [nsCenterOrOffice objectAtIndex:z];
[mapView addAnnotation:pm];


//in viewForAnnotation:
Placemark *myPlacemark = (Placemark *)annotation;
if ([myPlacemark.centerOrOffice isEqualToString:@"C"])
...


A separate, unrelated issue is that the annotation view creation logic is not quite right.
The code calls initWithAnnotation twice and in actuality the second initWithAnnotation never gets called since the first call will always succeed.

What you probably wanted was to first call dequeueReusableAnnotationViewWithIdentifier: and then, if that returns nil, call initWithAnnotation.

When restructuring the code in viewForAnnotation, be sure to put the code that sets the pinColor outside the dequeue/init of the annotation view (eg. right before the return annotationView;) to properly handle reused views.

查看更多
登录 后发表回答