地图视图显示我的位置和目的地,但不显示它们之间的路线

时间:2014-02-25 10:51:01

标签: ios mkmapview clgeocoder mkplacemark

当我初始化地图时,它会显示我的位置和目的地(从字符串进行地理编码),但它不会在它们之间绘制方向。

这是我的代码:

#import "EventDetailMapViewController.h"

@interface EventDetailMapViewController ()
@property (nonatomic,strong) MKMapItem *destination;
@end

@implementation EventDetailMapViewController

CLPlacemark *thePlacemark;
MKRoute *routeDetails;


- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    _mapView.showsUserLocation = YES;
    self.navigationController.toolbarHidden = NO;

    _mapView.delegate = self;
    [self getRoute];

}


- (void)addAnnotation:(CLPlacemark *)placemark {
    MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
    point.coordinate = CLLocationCoordinate2DMake(placemark.location.coordinate.latitude, placemark.location.coordinate.longitude);
    point.title = [placemark.addressDictionary objectForKey:@"Street"];
    point.subtitle = [placemark.addressDictionary objectForKey:@"City"];
    [self.mapView addAnnotation:point];
}



-(void)showRoute:(MKDirectionsResponse *)response{

    for (MKRoute *route in response.routes)
    {
        [_mapView
         addOverlay:route.polyline level:MKOverlayLevelAboveRoads];

        for (MKRouteStep *step in route.steps){
            NSLog(@"%@",step.instructions);
        }



    }

}

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    // If it's the user location, just return nil.
    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;
    // Handle any custom annotations.
    if ([annotation isKindOfClass:[MKPointAnnotation class]]) {
        // Try to dequeue an existing pin view first.
        MKPinAnnotationView *pinView = (MKPinAnnotationView*)[self.mapView dequeueReusableAnnotationViewWithIdentifier:@"CustomPinAnnotationView"];
        if (!pinView)
        {
            // If an existing pin view was not available, create one.
            pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"CustomPinAnnotationView"];
            pinView.canShowCallout = YES;
        } else {
            pinView.annotation = annotation;
        }
        return pinView;
    }
    return nil;
}
-(void)getRoute {
    [self getLocationFromString];

    MKDirectionsRequest *directionsRequest = [[MKDirectionsRequest alloc] init];
    MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:thePlacemark];
    [directionsRequest setSource:[MKMapItem mapItemForCurrentLocation]];
    [directionsRequest setDestination:[[MKMapItem alloc] initWithPlacemark:placemark]];
    directionsRequest.transportType = MKDirectionsTransportTypeAutomobile;
    MKDirections *directions = [[MKDirections alloc] initWithRequest:directionsRequest];
    [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
        if (error) {
            NSLog(@"Error %@", error.description);
        } else {
            routeDetails = response.routes.lastObject;
            [self.mapView addOverlay:routeDetails.polyline];

        }
    }];
}
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
    MKPolylineRenderer  * routeLineRenderer = [[MKPolylineRenderer alloc] initWithPolyline:routeDetails.polyline];
    routeLineRenderer.strokeColor = [UIColor redColor];
    routeLineRenderer.lineWidth = 5;
    return routeLineRenderer;
}


- (IBAction)changeMapType:(id)sender {
    if (_mapView.mapType == MKMapTypeStandard)
        _mapView.mapType = MKMapTypeSatellite;
    else
        _mapView.mapType = MKMapTypeStandard;
}


-(void)getLocationFromString{

    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder geocodeAddressString:self.agendaEntry.address completionHandler:^(NSArray *placemarks, NSError *error) {
        if (error) {
            NSLog(@"%@", error);
        } else {
            thePlacemark = [placemarks lastObject];
            float spanX = 1.00725;
            float spanY = 1.00725;
            MKCoordinateRegion region;
            region.center.latitude = thePlacemark.location.coordinate.latitude;
            region.center.longitude = thePlacemark.location.coordinate.longitude;
            region.span = MKCoordinateSpanMake(spanX, spanY);
            [self.mapView setRegion:region animated:YES];
            [self addAnnotation:thePlacemark];
        }
    }];
}

@end

我对此比较陌生,所以有些可能是错的。我想要的是当我按下一个按钮(在另一个视图中)时,“agendaEntry”会在segue上传递。它包含一个带地址的字符串,该地址进行前向地理编码,地图显示从用户位置到该字符串中地址的路线/路线。

我不知道如何让它显示驾驶/步行路线或让它显示多条路线。但对于初学者来说,如果能够奏效将会很棒。

1 个答案:

答案 0 :(得分:1)

它没有绘制路线的原因是因为在目标地标(thePlacemark)实际由geocodeAddressString完成处理程序块设置之前正在进行路线请求

请注意文档中有关geocodeAddressString:completionHandler:的内容:

  

此方法异步将指定的位置数据提交给地理编码服务器并返回。

因此,即使在方向请求之前调用getLocationFromString(调用geocodeAddressString),执行也会在getRoute启动后立即返回并继续geocodeAddressString(但不是完成)。

因此,当thePlacemark设置nil时,getRoute仍为directionsRequest,您可能会收到错误信息,例如“路线不可用”。

为了解决这个问题,您可以将调用方向请求设置代码移动到内部 geocodeAddressString完成处理程序块(在添加注释代码之后)。

有三件事需要改变:

  1. viewDidLoad中,执行[self getLocationFromString]; 而不是 [self getRoute];
  2. getRoute删除getLocationFromString的号召。
  3. getLocationFromString中,在完成处理程序块中,在[self addAnnotation:thePlacemark];之后,执行[self getRoute];


  4. 关于显示多条路线,首先您需要实际请求备用路线(默认为NO):

    directionsRequest.requestsAlternateRoutes = YES;
    

    您可能遇到的问题的另一部分是rendererForOverlay中的这一行:

    MKPolylineRenderer  * routeLineRenderer = [[MKPolylineRenderer alloc] 
        initWithPolyline:routeDetails.polyline];
    

    它使用外部实例变量而不是提供给委托方法的overlay参数创建折线渲染器。这基本上意味着委托方法仅适用于那个特定的覆盖(routeDetails.polyline),并且由于无法控制地图视图何时调用委托方法,因此无法可靠地设置{{1}从委托方法外部确保它指向正确的叠加层。每个备用路线都是单独的折线,地图视图会为每个路线单独调用routeDetails.polyline

    相反,请使用rendererForOverlay参数创建折线渲染器(并首先检查overlay是否为overlay):

    MKPolyline

    然后在-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay { if ([overlay isKindOfClass:[MKPolyline class]]) { MKPolylineRenderer * routeLineRenderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay]; routeLineRenderer.strokeColor = [UIColor redColor]; routeLineRenderer.lineWidth = 5; return routeLineRenderer; } return nil; } 中,而不是:

    getRoute

    调用已有的routeDetails = response.routes.lastObject; [self.mapView addOverlay:routeDetails.polyline]; 方法添加所有路由:

    showRoute