質問

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;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top