在 MKMapView 上自定义一个注解

Custom one annotation on MKMapView

我用MKPLaceMark填充我的地图,有一个具体的地址,这些标记对应一个会议。

我正在尝试自定义一个与下一次会议相对应的地标。

这是我的代码:

// Function to add all pin corresponding to all meeting.
- (void) addAllPins {
    _myMap.delegate = self;

    // Get all key of meeting
    NSArray* allKey = [[VSDataProvider sharedManager].startEvents allKeys];

    for (NSDate *date in allKey) {
        for (FFEvent *event in [[VSDataProvider sharedManager].startEvents objectForKey:date]) {

            // Retrieve with CLGeocoder the latitude and longitude with address of event
            NSString *localisation = [NSString stringWithFormat:@"%@ %@ %@ %@",event.street,event.zipCode,event.city,event.country];

            CLGeocoder *geocoder = [[CLGeocoder alloc] init];
            [geocoder geocodeAddressString:localisation completionHandler:^(NSArray *placemarks, NSError *error) {
                if (placemarks && placemarks.count > 0) {
                    CLPlacemark *topResult = [placemarks objectAtIndex:0];
                    MKPlacemark *place = [[MKPlacemark alloc] initWithPlacemark:topResult];
                    [arrayWithAllLocation addObject:place];
                    [self addPinWithTitle:event.street AndCoordinateLongitude:place.coordinate.longitude AndCoordinateLatitude:place.coordinate.latitude];
                }

                [self getCoordinateNexEvent:^{
                    for (MKPlacemark *mark in arrayWithAllLocation) {
                        if (mark.coordinate.latitude ==  _coordinateNextEvent.latitude && mark.coordinate.longitude == _coordinateNextEvent.longitude) {
                            MKAnnotationView *test = [[MKAnnotationView alloc]initWithAnnotation:mark reuseIdentifier:@"nextEvent"];
                            test.annotation = mark;
                            test.image = [UIImage imageNamed:@"Meeting.png"];
                            [_myMap addAnnotation:test.annotation]; 
                        }
                    }
                }];
            }];
        }
    }
}

// Retrieve coordinate for the next meeting
- (void) getCoordinateNexEvent :(void (^)(void))afterAll {
    FFEvent *event = [VSDataProvider sharedManager].nextEvent;
    CLGeocoder *geocoder = [[CLGeocoder alloc]init];
    NSString *localisation = [NSString stringWithFormat:@"%@ %@ %@ %@",event.street,event.zipCode,event.city,event.country];
    [geocoder geocodeAddressString:localisation completionHandler:^(NSArray *placemarks, NSError *error) {

        if (placemarks && placemarks.count > 0) {
            CLPlacemark *topResult = [placemarks objectAtIndex:0];
            placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
            _coordinateNextEvent.latitude = placemark.coordinate.latitude;
            _coordinateNextEvent.longitude = placemark.coordinate.longitude;
        }

        afterAll();
    }];
}

// This method add a Pin with the title and coordinate
- (void) addPinWithTitle : (NSString*)title AndCoordinateLongitude : (double)coordinateLongitude AndCoordinateLatitude : (double)coordinateLatitue {
    MKPointAnnotation *mapPin = [[MKPointAnnotation alloc]init];
    CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(coordinateLatitue, coordinateLongitude);
    mapPin.title = title;
    mapPin.coordinate = coordinate;
    [self.myMap addAnnotation:mapPin];
}

- (void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {    
    MKCoordinateRegion region;
    MKCoordinateSpan span;

    span.latitudeDelta = 0.5;
    span.longitudeDelta = 0.5;

    CLLocationCoordinate2D location;
    location.latitude = userLocation.coordinate.latitude;
    location.longitude = userLocation.coordinate.longitude;

    region.span = span;
    region.center = location;

    [_myMap setRegion:region animated:YES];
}

当我使用

- (MKAnnotationView*) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {

    __block MKAnnotationView *annotationWithNextEvent;

    annotationWithNextEvent = (MKAnnotationView*) [_myMap dequeueReusableAnnotationViewWithIdentifier:@"nextEventAnnotation"];

    if (!annotationWithNextEvent) {

        annotationWithNextEvent = [[MKAnnotationView alloc] initWithAnnotation:placemark reuseIdentifier:@"nextEventAnnotation"];
    }
    annotationWithNextEvent.image = [UIImage imageNamed:@"Meeting.png"];
    annotationWithNextEvent.annotation = annotation;
    return annotationWithNextEvent;
}

所有注释都是图片,我不要这个。

我希望我清楚

您应该像下面这样为其创建子类:

@interface MeetingPointAnnotation : MKPointAnnotation
@property (strong, nonatomic) NSString *customData;
@end

然后检查它:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
    if ([annotation isKindOfClass:[MeetingPointAnnotation class]]) {
        __block MKAnnotationView *annotationWithNextEvent;
        annotationWithNextEvent = (MKAnnotationView*) [_myMap dequeueReusableAnnotationViewWithIdentifier:@"nextEventAnnotation"];
        
        if (!annotationWithNextEvent) {
            annotationWithNextEvent = [[MKAnnotationView alloc] initWithAnnotation:placemark reuseIdentifier:@"nextEventAnnotation"];
        }
        
        annotationWithNextEvent.image = [UIImage imageNamed:@"Meeting.png"];
        annotationWithNextEvent.annotation = annotation;
        return annotationWithNextEvent;
    }
    return nil;
}

这将仅自定义该类型的注释

您的代码也可能与 CLGeocoder 有问题,因为它可能会经常使用它。阅读文档:

Applications should be conscious of how they use geocoding. Geocoding requests are rate-limited for each app, so making too many requests in a short period of time may cause some of the requests to fail. (When the maximum rate is exceeded, the geocoder returns an error object with the value kCLErrorNetwork to the associated completion handler.) Here are some rules of thumb for using this class effectively:

  • Send at most one geocoding request for any one user action.

  • If the user performs multiple actions that involve geocoding the same location, reuse the results from the initial geocoding request instead of starting individual requests for each action.

  • When you want to update the user’s current location automatically (such as when the user is moving), issue new geocoding requests only when the user has moved a significant distance and after a reasonable amount of time has passed. For example, in a typical situation, you should not send more than one geocoding request per minute.

  • Do not start a geocoding request at a time when the user will not see the results immediately. For example, do not start a request if your application is inactive or in the background.