原生地图---iOS笔记摘录

目录
     1. 地图
          1.1 大头针(即标注)
          1.2 Overlay覆盖物
          1.3 MKMapViewDelegate
          1.4 苹果原生地图App
     2. 定位
          2.1 地理编码与反编码     
     3. POI检索
     4. 相关类

注意:

iOS8.0后 地图需要权限(info.plist中添加):
  NSLocationAlwaysUsageDescription          始终需要
或者
  NSLocationWhenInUseUsageDescription       仅在使用期间

CLLocationManager中相应两个请求权限的方法:
  requestAlwaysAuthorization
  requestWhenInUseAuthorization

模拟器默认没有地理位置,可使用调试栏中的箭头设置地理坐标

使用

0.导入MapKit框架 
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

<MKMapViewDelegate>
1. 地图
MKMapView

    // :UIView
    MKMapView *mapView=[MKMapView new];
    [self.view addSubview:mapView];
    // 地图类型
    mapView.mapType=MKMapTypeStandard;
    /**
     MKMapTypeStandard  :标准地图(常用)显示街道
     MKMapTypeSatellite :卫星地图
     MKMapTypeHybrid    :混合地图(加载最慢,消耗资源)卫星地图上显示街道
     MKMapTypeSatelliteFlyover NS_ENUM_AVAILABLE(10_11, 9_0),//立体卫星
     MKMapTypeHybridFlyover NS_ENUM_AVAILABLE(10_11, 9_0),//立体混合
     */
用户位置

    // 是否显示用户位置
    [mapV setShowsUserLocation:true];
    // 用户位置是否可见(readOnly)
    BOOL isShowUser=mapV.userLocationVisible;
    // 用户追踪类型
    MKUserTrackingMode tankMode=mapV.userTrackingMode;
    // 追踪类型(显示用户位置)
    [mapV setUserTrackingMode: MKUserTrackingModeNone];
    [mapV setUserTrackingMode: MKUserTrackingModeNone animated:true];
    /**
     MKUserTrackingModeNone              : 不追踪;
     MKUserTrackingModeFollow            : 追踪用户位置;
     MKUserTrackingModeFollowWithHeading : 追踪用户位置并且追踪用户前进方向;
     */
    // 用户位置(readonly)
    MKUserLocation *userLocation=mapView.userLocation;
    /**
     userLocation.location   // location
     userLocation.subtitle   // 用户所在位置的Annotation的subTitle
     userLocation.title      // 用户所在位置的Annotation的title
     userLocation.heading    //
     userLocation.isUpdating // 是否持续更新
     */

交互

    // 是否允许缩放
    [mapV setZoomEnabled:true];
    // 是否允许滚动
    [mapV setScrollEnabled:true];
    // 是否允许旋转
    [mapV setRotateEnabled:true];
    // 是否支持3D地图
    [mapV setPitchEnabled:true];
    // 是否显示兴趣点
    [mapV setShowsPointsOfInterest:true];
    // 是否显示建筑物轮廓(尽在标准地图中有效)
    [mapV setShowsBuildings:true];
    // 是否显示罗盘
    [mapV setShowsCompass:true];
    // 是否显示缩放比例尺
    [mapV setShowsScale:true];
    // 是否显示交通拥堵状况
    [mapV setShowsTraffic:true];
中心位置

    // 设置地图的中心点
    [mapV setCenterCoordinate:CLLocationCoordinate2DMake(39, 116)];
    [mapV setCenterCoordinate:CLLocationCoordinate2DMake(39, 116) animated:true];
    
    // 设置地图的显示范围(中心点经纬度,显示经纬度范围)(纬度39~41,经度116~118)
    [mapV setRegion:MKCoordinateRegionMake(CLLocationCoordinate2DMake(39, 116), MKCoordinateSpanMake(2, 2))];
    [mapV setRegion:MKCoordinateRegionMake(CLLocationCoordinate2DMake(39, 116), MKCoordinateSpanMake(2, 2)) animated:true];

/**
    typedef struct {
        CLLocationCoordinate2D center;      // 地图中心的经纬度
        MKCoordinateSpan span;              // 地图显示的经纬度范围
    } MKCoordinateRegion;
    //
    typedef struct {
        CLLocationDegrees latitude;         // 纬度,北纬为正
        CLLocationDegrees longitude;        // 经度,东经为正
    } CLLocationCoordinate2D;
    typedef struct {
        CLLocationDegrees latitudeDelta;    // 纬度范围(0~180) 超了会崩
        CLLocationDegrees longitudeDelta;   // 经度范围(0-360)
    } MKCoordinateSpan;
*/
坐标转换

    // 将 地理坐标点 转换为 代码坐标点
    CGPoint point=[mapV convertCoordinate:CLLocationCoordinate2DMake(39, 116) toPointToView:[UIView new]];
    // 将 代码坐标点 转换为 地理坐标点
    CLLocationCoordinate2D location=[mapV convertPoint:CGPointMake(0, 100) toCoordinateFromView:[UIView new]];

    // 将 地理坐标区域 转换为 代码坐标区域
    CGRect rect=[mapV convertRegion:MKCoordinateRegionMake(CLLocationCoordinate2DMake(39, 116), MKCoordinateSpanMake(2, 2)) toRectToView:[UIView new]];
    // 将 代码坐标区域 转换为 地理坐标区域
    MKCoordinateRegion region=[mapV convertRect:CGRectMake(0, 0, 100, 200) toRegionFromView:[UIView new]];

1.1 大头针(即标注)

    // 1. 添加大头针(可以自定义<MKAnnotation>)
    MKPointAnnotation *pointAn=[MKPointAnnotation new];
    // 大头针位置
    [pointAn setCoordinate:CLLocationCoordinate2DMake(39.1, 116.1)];
    // 大头针下边标题
    [pointAn setTitle:@"title"];
    // 大头针下边副标题
    [pointAn setSubtitle:@"subTitle"];
    [mapV addAnnotation:pointAn];

// 2. 重绘大头针视图---不写时为默认视图<MKMapViewDelegate>
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
    //
    if(![annotation isKindOfClass:[大头针自定义类 class]]){
        //
        MKAnnotationView *annotationView=[mapView dequeueReusableAnnotationViewWithIdentifier:@"iden"];
        if(!annotationView){
            annotationView=[[MKAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:@"iden"];

            // 设置可拖拽(默认:false)
            annotationView.draggable=YES;

            // 允许弹出气泡(点击后弹出,默认:false)
            annotationView.canShowCallout=true;   
            // 气泡视图偏移量
            annotationView.calloutOffset=CGPointMake(0, 1);                   
            // 气泡视图右侧视图 
            aniView.rightCalloutAccessoryView=[UIView new];
            // 气泡视图左侧视图
            annotationView.leftCalloutAccessoryView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"气泡视图左侧视图"]];
        }

    
        return annotationView;
    }
    return nil;
}
MKPointAnnotation大头针(即标注)

    // 获取所有大头针(readOnly)
    NSArray *annotationArr=mapView.annotations;
    
    // 添加/移除大头针
    [mapView addAnnotation:<#(nonnull id<MKAnnotation>)#>];
    [mapV addAnnotations:<#(nonnull NSArray<id<MKAnnotation>> *)#>];
    [mapView removeAnnotation:<#(nonnull id<MKAnnotation>)#>];
    [mapV removeAnnotations:<#(nonnull NSArray<id<MKAnnotation>> *)#>];

    // 注册大头针
    [mapV registerClass:[Class class] forAnnotationViewWithReuseIdentifier:@"iden"];
    // 获取指定区域内的大头针
    NSSet<id<MKAnnotation>> *rectAnnimation=[mapV annotationsInMapRect:MKMapRectMake(0, 0, 30, 30)];
    // 获取大头针视图
    MKAnnotationView *anView=[mapV viewForAnnotation:<#(nonnull id<MKAnnotation>)#>];
    // 获取大头针视图(复用)
    MKAnnotationView *anView=[mapV dequeueReusableAnnotationViewWithIdentifier:@""];
    MKAnnotationView *anView=[mapV dequeueReusableAnnotationViewWithIdentifier:@"" forAnnotation:<#(nonnull id<MKAnnotation>)#>];


    // 选中指定大头针
    [mapView selectAnnotation:<#(nonnull id<MKAnnotation>)#> animated:<#(BOOL)#>];
    // 取消选中指定大头针
    [mapView deselectAnnotation:<#(nullable id<MKAnnotation>)#> animated:<#(BOOL)#>];
    // 获取所有选中的大头针
    NSArray<id<MKAnnotation>> *selectAniArr=mapV.selectedAnnotations;
    // 大头针视图rect(readOnly)
    CGRect anRect=mapV.annotationVisibleRect;
    // 显示大头针
    [mapV showAnnotations:@[] animated:true];



<MKAnnotation>协议 (自定义大头针必须 遵守)
  @protocol MKAnnotation <NSObject>
  @property (nonatomic, readonly) CLLocationCoordinate2D coordinate; // 地理坐标
  @optional
  @property (nonatomic, readonly, copy) NSString *title;        // 标题
  @property (nonatomic, readonly, copy) NSString *subtitle;     // 副标题
  - (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate;  // 拖动时调用
  @end



MKAnnotationView
    // 创建可复用
    MKAnnotationView *aniView=[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:@"system"];

    // 获取复用标识符(readOnly)
    NSString *reuseIdentifier=aniView.reuseIdentifier;
    // 大头针
    id <MKAnnotation> ani=aniView.annotation;
    // 大头针图片
    [aniView setImage:[UIImage imageNamed:@""]];
    // 设置大头针偏移量
    [aniView setCenterOffset:CGPointMake(0, 0)];
    // 设置气泡偏移量
    [aniView setCalloutOffset:CGPointMake(0, 0)];
    // 是否可点击(默认:false)
    @property (nonatomic, getter=isEnabled) BOOL enabled;
    // 是否允许高亮(默认:false)
    @property (nonatomic, getter=isHighlighted) BOOL highlighted;
    // 是否选中(默认:false)
    @property (nonatomic, getter=isSelected) BOOL selected;
    [aniView setSelected:true animated:true];
    // 是否显示气泡(显示则必须有title)
    @property (nonatomic) BOOL canShowCallout;
    // 是否可拖拽
    @property (nonatomic, getter=isDraggable) BOOL draggable;
    // 拖拽状态
    @property (nonatomic) MKAnnotationViewDragState dragState;
    [aniView setDragState:MKAnnotationViewDragStateEnding animated:true];

    // 气泡附件视图
    @property (strong, nonatomic, nullable) UIView *leftCalloutAccessoryView;
    @property (strong, nonatomic, nullable) UIView *rightCalloutAccessoryView;
    @property (nonatomic, strong, nullable) UIView *detailCalloutAccessoryView;

    // 用于覆写(必须调super)
    - (void)prepareForReuse;
    - (void)prepareForDisplay;

    // ?
    @property (nonatomic, copy, nullable) NSString *clusteringIdentifier;
    // (readOnly)
    MKAnnotationView *clusterAnnotationView=aniView.clusterAnnotationView;
    @property (nonatomic) MKFeatureDisplayPriority displayPriority;
    @property (nonatomic) MKAnnotationViewCollisionMode collisionMode;


    拖拽状态
    typedef NS_ENUM(NSUInteger, MKAnnotationViewDragState) {
        MKAnnotationViewDragStateNone = 0,      
        MKAnnotationViewDragStateStarting,
        MKAnnotationViewDragStateDragging,
        MKAnnotationViewDragStateCanceling,
        MKAnnotationViewDragStateEnding
    }



MKPinAnnotationView:MKAnnotationView
    // 大头针是否从天而降
    aniView.animatesDrop=true;
    // 大头针颜色
    aniView.pinTintColor=[UIColor yellowColor];

1.2 Overlay覆盖物

折线

    // 1. 添加覆盖物
    // 点数据
    CLLocationCoordinate2D *coor = malloc(sizeof(CLLocationCoordinate2D)*5);
    for (int i=0; i<5; i++) {
        CLLocationCoordinate2D po = CLLocationCoordinate2DMake(39.23+i*0.01, 116.112+i*0.01);
        coor[i]=po;
    }
    // 创建一个折线
    MKPolyline * line = [MKPolyline polylineWithCoordinates:coor count:5];
    [mapV addOverlay:line];

// 2. 重新绘制覆盖物
// 覆盖物绘制的代理
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
    
    // 折线覆盖物提供者
    MKPolylineRenderer * render = [[MKPolylineRenderer alloc]initWithPolyline:overlay];
    // 设置线宽
    render.lineWidth=3;
    // 设置颜色
    render.strokeColor=[UIColor redColor];
    
    return render;
}
圆

    // 1. 添加覆盖物
    MKCircle * cirle = [MKCircle circleWithCenterCoordinate:CLLocationCoordinate2DMake(39, 116) radius:500];
    [mapV addOverlay:cirle];

// 2. 绘制覆盖物
// 覆盖物绘制的代理
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
    
    MKCircleRenderer * render=[[MKCircleRenderer alloc]initWithCircle:overlay];
    // 宽
    render.lineWidth=3;
    // 填充颜色
    render.fillColor=[UIColor greenColor];
    // 边框颜色
    render.strokeColor=[UIColor redColor];
    
    return render;
}
多边形

    // 1. 添加覆盖物
    CLLocationCoordinate2D *coor;
    coor = malloc(sizeof(CLLocationCoordinate2D)*6);
    for (int i=0; i<5; i++) {
        CLLocationCoordinate2D po = CLLocationCoordinate2DMake(36+i*0.01, 116+((i/3==0)?0.1:-0.1));
        coor[i]=po;
    }
    coor[5]=CLLocationCoordinate2DMake(36, 116);
    MKPolygon * gon = [MKPolygon polygonWithCoordinates:coor count:6];
    [mapV addOverlay:gon];

// 2. 绘制覆盖物
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
    
    MKPolygonRenderer * render = [[MKPolygonRenderer alloc]initWithPolygon:overlay];
    render.lineWidth=3;
    render.strokeColor=[UIColor redColor];
    return render;
}
Overlay覆盖物

    //
    NSArray *overArr=mapV.overlays;  // 获取所有覆盖物(readOnly)
    // 获取覆盖物render
    MKOverlayRenderer *overRender=[mapV rendererForOverlay:<#(nonnull id<MKOverlay>)#>];
    NSArray *overAr=[mapV overlaysInLevel:MKOverlayLevelAboveRoads];
    // 替换/插入/添加/移除覆盖物
    [mapV exchangeOverlay:<#(nonnull id<MKOverlay>)#> withOverlay:<#(nonnull id<MKOverlay>)#>];
    [mapV exchangeOverlayAtIndex:<#(NSUInteger)#> withOverlayAtIndex:<#(NSUInteger)#>];
    [mapV insertOverlay:<#(nonnull id<MKOverlay>)#> atIndex:0];
    [mapV insertOverlay:<#(nonnull id<MKOverlay>)#> atIndex:0 level:MKOverlayLevelAboveRoads];
    [mapV insertOverlay:<#(nonnull id<MKOverlay>)#> aboveOverlay:<#(nonnull id<MKOverlay>)#>];
    [mapV insertOverlay:<#(nonnull id<MKOverlay>)#> belowOverlay:<#(nonnull id<MKOverlay>)#>];
    [mapV addOverlays:<#(nonnull NSArray<id<MKOverlay>> *)#>];
    [mapV addOverlay:<#(nonnull id<MKOverlay>)#>];
    [mapV addOverlay:<#(nonnull id<MKOverlay>)#> level:MKOverlayLevelAboveRoads];
    /*
     typedef NS_ENUM(NSInteger, MKOverlayLevel) {
        MKOverlayLevelAboveRoads = 0,   // 覆盖物在道路上
        MKOverlayLevelAboveLabels       // 覆盖物在标签上
     }
     */
    [mapV removeOverlay:<#(nonnull id<MKOverlay>)#>];
    [mapV removeOverlays:<#(nonnull NSArray<id<MKOverlay>> *)#>];


自定义覆盖物必须遵守<MKOverlay>

1.3 MKMapViewDelegate

<MKMapViewDelegate>

            [mapView setDelegate:self];    // MKMapViewDelegate
// 地图将要加载时调用
-(void)mapViewWillStartLoadingMap:(MKMapView *)mapView{}
// 地图加载完成后调用
-(void)mapViewDidFinishLoadingMap:(MKMapView *)mapView{}
// 地图加载失败后调用
-(void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error{}
// 地图将要绘制时调用
-(void)mapViewWillStartRenderingMap:(MKMapView *)mapView{}
// 地图绘制完后调用
-(void)mapViewDidFinishRenderingMap:(MKMapView *)mapView fullyRendered:(BOOL)fullyRendered{}


// 地图显示位置将要改变时调用
-(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated{}
// 地图显示位置改变后调用
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated{}


// 添加大头针后调用
-(void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views{}
// 自定义大头针
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{}
// 选中某一大头针
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{}
// 取消选中某一大头针
-(void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view{}
// 点击气泡中的附件后调用
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control{}
// 大头针的拖动位置改变后调用
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState{}
    /*
     typedef NS_ENUM(NSUInteger, MKAnnotationViewDragState) {
        MKAnnotationViewDragStateNone = 0,      // 初始状态
        MKAnnotationViewDragStateStarting,      // 开始拖动时
        MKAnnotationViewDragStateDragging,      // 正在拖动
        MKAnnotationViewDragStateCanceling,     // 取消拖动
        MKAnnotationViewDragStateEnding         // 结束拖动
     };
     */
// 自定义覆盖物
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{}
// 添加覆盖物后调用
-(void)mapView:(MKMapView *)mapView didAddOverlayRenderers:(NSArray<MKOverlayRenderer *> *)renderers{}
// ?
-(MKClusterAnnotation *)mapView:(MKMapView *)mapView clusterAnnotationForMemberAnnotations:(NSArray<id<MKAnnotation>> *)memberAnnotations{}


// 将要定位用户位置时调用
-(void)mapViewWillStartLocatingUser:(MKMapView *)mapView{}
// 停止定位用户位置后调用
-(void)mapViewDidStopLocatingUser:(MKMapView *)mapView{}
// 定位用户位置失败后调用
-(void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error{}
// 用户位置更新时调用
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{}
// 改变用户定位模式后调用
-(void)mapView:(MKMapView *)mapView didChangeUserTrackingMode:(MKUserTrackingMode)mode animated:(BOOL)animated{}
    // ?
    MKCoordinateRegion region=[mapV regionThatFits:MKCoordinateRegionMake(CLLocationCoordinate2DMake(36, 116), MKCoordinateSpanMake(1, 1))];
    // ?
    MKMapRect mapRect=[mapV mapRectThatFits:MKMapRectMake(0, 0, 30, 30)];
    MKMapRect mapRect=[mapV mapRectThatFits:MKMapRectMake(0, 0, 30, 30) edgePadding:UIEdgeInsetsZero];
    // ?
    MKMapRect mapRect=[mapV visibleMapRect];
    [mapV setVisibleMapRect:[MKMapRectMake(0, 0, 30, 30)]];
    [mapV setVisibleMapRect:MKMapRectMake(0, 0, 30, 30) animated:true];
    [mapV setVisibleMapRect:MKMapRectMake(0, 0, 30, 30) edgePadding:UIEdgeInsetsZero animated:true];
    /*
     typedef struct {
        MKMapPoint origin;
        MKMapSize size;
     } MKMapRect;
     typedef struct {
        double x;
        double y;
     } MKMapPoint;
     typedef struct {
        double width;
        double height;
     } MKMapSize;
     typedef struct {
        MKMapPoint origin;
        MKMapSize size;
     } MKMapRect;
     */


    // ?
    MKMapCamera *mapCamera=[mapV camera];
    [mapV setCamera:[MKMapCamera cameraLookingAtCenterCoordinate:CLLocationCoordinate2DMake(36, 116) fromDistance:CLLocationDistanceMax pitch:0.5 heading:kCFLocaleLanguageDirectionLeftToRight]];

1.4. 苹果原生地图App

           //
            [[CLGeocoder new]geocodeAddressString:@"山西" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
                CLPlacemark *placeMark=[placemarks firstObject];
                
                // 跳转到苹果原生App,并标注一个点
                MKPlacemark *mPlaceMark=[[MKPlacemark alloc]initWithPlacemark:placeMark];
                MKMapItem *mItem=[[MKMapItem alloc]initWithPlacemark:mPlaceMark];
                [mItem openInMapsWithLaunchOptions:@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)}];
                
                
                // 添加多个标注
                [MKMapItem openMapsWithItems:@[mItem,mItem2] launchOptions:@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard)];
                
                
                // 导航
                [MKMapItem openMapsWithItems:@[mItem,mItem2] launchOptions:@{MKLaunchOptionsMapTypeKey:@(MKMapTypeStandard),MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving}];
            }];
2. 定位

定位

<CLLocationManagerDelegate>{
    CLLocationManager *locationManger; //(必须是全局的,否则出现请求定位弹窗就消失)
}

-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    
    locationManger=nil;
}
-(void)viewWillAppear:(BOOL)animated{
    
    [super viewWillAppear:animated];
    
    //
    locationManger.delegate=self;
    // 定位精度(越精确越耗电,定位速度越慢)
    locationManger.desiredAccuracy=kCLLocationAccuracyNearestTenMeters;     
    /**
     kCLLocationAccuracyBest:最精确定位
     kCLLocationAccuracyNearestTenMeters:十米误差范围
     kCLLocationAccuracyHundredMeters:百米误差范围
     kCLLocationAccuracyKilometer:千米误差范围
     kCLLocationAccuracyThreeKilometers:三千米误差范围
     */
    locationManger.distanceFilter=50;               // 每隔50m定位一次
    [locationManger startUpdatingLocation];         // 开始定位
}
-(void)viewDidLoad{
    
    [super viewDidLoad];
    
    // 定位管理器
    locationManger=[CLLocationManager new];
    if(![CLLocationManager locationServicesEnabled]){
        NSLog(@"定位 服务关闭");
        return;
    }else if ([CLLocationManager authorizationStatus]==kCLAuthorizationStatusNotDetermined){
        /**
         kCLAuthorizationStatusNotDetermined: 用户尚未做出决定是否启用定位服务
         kCLAuthorizationStatusRestricted: 没有获得用户授权使用定位服务,可能用户没有自己禁止访问授权
         kCLAuthorizationStatusDenied :用户已经明确禁止应用使用定位服务或者当前系统定位服务处于关闭状态
         kCLAuthorizationStatusAuthorizedAlways: 应用获得授权可以一直使用定位服务,即使应用不在使用状态
         kCLAuthorizationStatusAuthorizedWhenInUse: 使用此应用过程中允许访问定位服务
         */
        
        // 请求定位授权
        [locationManger requestWhenInUseAuthorization]; // 需在info.plist中+NSLocationWhenInUseUsageDescription
        //                [locationManger requestAlwaysAuthorization];    // 需在info.plist中+NSLocationAlwaysUsageDescription
    }
}
// 地址更新后回调
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{

    [manager stopUpdatingLocation];
    CLLocation *location=[locations firstObject];
    CLLocationCoordinate2D loc=location.coordinate;
    
    // 反地理编码
    CLGeocoder *myGeocoder = [CLGeocoder new];
    // 坐标转地名
    [myGeocoder reverseGeocodeLocation:[[CLLocation alloc]initWithLatitude:loc.latitude longitude:loc.longitude] completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        
        //
        CLPlacemark *placeMark=[placemarks firstObject];
        CLLocation *location=[placeMark location];
        _currentLocation=location;
        
        // 
    }];
}

监听方向

     [locationManger startUpdatingHeading];          // 开始监听用户方向
     [locationManger stopUpdatingHeading];           // 停止监听用户方向
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading{
}

监听区域

     [locationManger startMonitoringForRegion:];   // 监听 进入/离开某区域
     [locationManger stopMonitoringForRegion:];    // stop 监听
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region{
}

2.1 地理 编码和反编码

放在didUpdateLocations方法中获取地址信息

            //
            CLGeocoder *myGeocoder = [CLGeocoder new];
            // 坐标转地名
            [myGeocoder reverseGeocodeLocation:[[CLLocation alloc]initWithLatitude:39.54 longitude:116.0] completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
                //
                CLPlacemark *placeMark=[placemarks firstObject];
                NSDictionary *addressDic=placeMark.addressDictionary;  // detail {"Name":地名,@"State":省名,@"City":市名,@"Country":国家}
            }];



            // 地名转坐标
            [myGeocoder geocodeAddressString:@"北京" completionHandler:^(NSArray *placeMarks, NSError *error) {
                //
                if ([placeMarks count] > 0 && error == nil) {
                    
                    // 拿到第一个坐标
                    CLPlacemark *placeMark=[placeMarks firstObject];
                    CLLocation *location=placeMark.location;       // location
/**
                    CLRegion *region=placeMark.region;                     // region
                    NSDictionary *addressDic=placeMark.addressDictionary;  // detail
                    NSString *name=placeMark.name;                         // 地名
                    NSString *thoroughfare=placeMark.thoroughfare;         // 街道
                    NSString *subThoroughfare=placeMark.subThoroughfare;   // 街道相关信息,例如门牌等
                    NSString *locality=placeMark.locality;                 // 城市
                    NSString *subLocality=placeMark.subLocality;           // 城市相关信息,例如标志性建筑
                    NSString *administrativeArea=placeMark.administrativeArea;         // 州
                    NSString *subAdministrativeArea=placeMark.subAdministrativeArea;   // 其他行政区域信息
                    NSString *postalCode=placeMark.postalCode;             // 邮编
                    NSString *ISOcountryCode=placeMark.ISOcountryCode;     // 国家编码
                    NSString *country=placeMark.country;                   // 国家
                    NSString *inlandWater=placeMark.inlandWater;           // 水源、湖泊
                    NSString *ocean=placeMark.ocean;                       // 海洋
                    NSArray *areasOfInterest=placeMark.areasOfInterest;    // 关联的或利益相关的地标
*/
                    //
                    NSLog(@"获得地理编码经度 = %f", placeMark.location.coordinate.longitude);
                    NSLog(@"获得地理编码纬度 = %f", placeMark.location.coordinate.latitude);
                }else if ([placeMarks count] == 0 && error == nil) {
                    NSLog(@"Found no placeMarks.");
                }else if (error != nil) {
                    NSLog(@"An error occurred = %@", error);
                }
            }];
1.导航---获取路线
// 1.创建出发和结束节点
    // 设置导航起始经纬度
    CLLocationCoordinate2D fromcoor=CLLocationCoordinate2DMake(36, 116);
    CLLocationCoordinate2D tocoor = CLLocationCoordinate2DMake(36.8, 116.8);
    // 创建出发点和目的点信息
    MKPlacemark *fromPlace = [[MKPlacemark alloc] initWithCoordinate:fromcoor addressDictionary:nil];
    MKPlacemark *toPlace = [[MKPlacemark alloc]initWithCoordinate:tocoor addressDictionary:nil];
    // 创建出发节点和目的地节点
    MKMapItem * fromItem = [[MKMapItem alloc]initWithPlacemark:fromPlace];
    MKMapItem * toItem = [[MKMapItem alloc]initWithPlacemark:toPlace];
    
// 2.创建导航搜索请求
    MKDirectionsRequest *request = [[MKDirectionsRequest alloc]init];
    request.source=fromItem;    // 出发节点
    request.destination=toItem; // 结束节点
    request.requestsAlternateRoutes=YES;    //
    
// 3.开始检索(结果会返回在block中)
    MKDirections *directions = [[MKDirections alloc]initWithRequest:request];
    [directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
        if (error) {
            NSLog(@"error:%@",error);
        }else{

// 4.获取到路线( 绘制 标注和路线)
            // 提取导航线路结果中的一条线路
            MKRoute *route =response.routes[0];
            // 提取线路中的每一步
            NSArray * stepArray = [NSArray arrayWithArray:route.steps];
            // 遍历每一步
            for (int i=0; i<stepArray.count; i++) {
                // 在每一个拐点中添加一个大头针
                MKRouteStep * step = stepArray[i];
                MKPointAnnotation * point = [[MKPointAnnotation alloc]init];
                point.coordinate=step.polyline.coordinate;
                point.title=step.instructions;
                point.subtitle=step.notice;
                [mapV addAnnotation:point];
                
                // 将此段线路添加到地图上
                [mapV addOverlay:step.polyline];
            }
        }
    }];
// 覆盖物
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
    MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
    renderer.strokeColor = [UIColor redColor];
    renderer.lineWidth = 4.0;
    
    return  renderer;
}

// 标注
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
    MKPinAnnotationView * view= [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:@"anno"];
    view.canShowCallout=YES;
    
    return view;
}
  1. POI检索
    周边搜索(根据关键字和搜索范围)
-(void)search:(NSString *)searchStr{
    // 周边搜索 请求类(设置条件进行查询)
    MKLocalSearchRequest *localSearchRequest = [[MKLocalSearchRequest alloc] init];
    // 设置 搜索范围
    MKCoordinateSpan span = MKCoordinateSpanMake(0.6250, 0.6250);
    MKCoordinateRegion region = MKCoordinateRegionMake(_currentLocation.coordinate, span);
    localSearchRequest.region = region;                 
    // 设置 搜索关键词
    localSearchRequest.naturalLanguageQuery = searchStr;

    // 周边搜索类
    MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:localSearchRequest];
    // 开始搜索
    [localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
        NSLog(@"count:%ld",response.mapItems.count);
        if (error){
            NSLog(@"error:%@",error);
        }else{        NSLog(@"name:%@,\nthoroughfare:%@,\nsubThoroughfare:%@,\nlocality:%@,\nsubLocality:%@,\nadministrativeArea:%@,\nsubAdministrativeArea:%@,\ncountry:%@,\ninlandWater:%@,\nocean:%@",mapItem.placemark.name,mapItem.placemark.thoroughfare,mapItem.placemark.subThoroughfare,mapItem.placemark.locality,mapItem.placemark.subLocality,mapItem.placemark.administrativeArea,mapItem.placemark.subAdministrativeArea,mapItem.placemark.country,mapItem.placemark.inlandWater,mapItem.placemark.ocean);
            }
        }
    }];
}
4. 相关类

4.1 CLLocationManager

CLLocationManager 位置管理者


    // 获取 当前定位是否授权
    CLAuthorizationStatus status=[CLLocationManager authorizationStatus];
     /*
     // 用户还没选择是否授权
     kCLAuthorizationStatusNotDetermined
     // 用户拒绝授权
     kCLAuthorizationStatusDenied
     // 始终允许
     kCLAuthorizationStatusAuthorizedAlways
     // 使用期间允许
     kCLAuthorizationStatusAuthorizedWhenInUse
     // 应用拒绝使用定位
     kCLAuthorizationStatusRestricted
     */
    // 设备是否支持定位服务
    BOOL isCanLocation=[CLLocationManager locationServicesEnabled];
    // 请求用户位置权限---使用期间
    [locationManger requestWhenInUseAuthorization];
    // 请求用户位置权限---始终
    [locationManger requestAlwaysAuthorization];
    // 请求一次位置
    [locationManger requestLocation];



    // 设置 位置更新的模式
    [locationManger setActivityType:CLActivityTypeOther];
     /*
     CLActivityTypeOther = 1                         未知
     CLActivityTypeAutomotiveNavigation              车辆导航模式
     CLActivityTypeFitness                           步行模式
     CLActivityTypeOtherNavigation                   其他交通工具模式
     */
    // 设置 最小的更新距离为 50m(低于50不更新)
    [locationManger setDistanceFilter:50];
    // 设置 最小的方向改变角度,低于角度不更新
    [locationManger setHeadingFilter:10];
    // 设置 定位精准度(越精确越费电)
    [locationManger setDesiredAccuracy:kCLLocationAccuracyBest];
    /*
       kCLLocationAccuracyBestForNavigation       最高精确
       kCLLocationAccuracyBest                    高精确
       kCLLocationAccuracyNearestTenMeters        10米
       kCLLocationAccuracyHundredMeters           百米
       kCLLocationAccuracyKilometer               千米
       kCLLocationAccuracyThreeKilometers         三公里
     */
    // 设置 位置更新是否自动停止(位置不变时停止更新)
    [locationManger setPausesLocationUpdatesAutomatically:true];
    // 设置导航方向,以正北为参照物
    [locationManger setHeadingOrientation:CLDeviceOrientationPortrait];
     /*
      typedef NS_ENUM(int, CLDeviceOrientation) {
        CLDeviceOrientationUnknown = 0 ,        // 方向未知
        CLDeviceOrientationPortrait,            // 纵向模式
        CLDeviceOrientationPortraitUpsideDown,  // 纵向倒置模式
        CLDeviceOrientationLandscapeLeft,       // 左向横向模式
        CLDeviceOrientationLandscapeRight,      // 右向横向模式
        CLDeviceOrientationFaceUp,              // 水平屏幕向上模式
        CLDeviceOrientationFaceDown             // 水平屏幕下模式
      };
     */
    // 设置 立刻隐藏方向标(方向改变后稳定前 会出现)
    [locationManger dismissHeadingCalibrationDisplay];
    // 设置 是否允许后台刷新
    [locationManger setAllowsBackgroundLocationUpdates:true];
    // 设置 处于后台使用位置时手机上方是否显示正在使用(默认:false)
    [locationManger setShowsBackgroundLocationIndicator:true];
    // ?
    [locationManger requestStateForRegion:[CLRegion new]];


位置更新
    // 设备是否支持监测位置更新变换
    BOOL isCanMonitor=[CLLocationManager significantLocationChangeMonitoringAvailable];
    // 获取 最后更新的位置(readOnly)
    CLLocation location=locationManger.location;
    // 开始/结束监测位置变化
    [locationManger startUpdatingLocation];
    [locationManger stopUpdatingLocation];
    // 开始/结束监测?变化
    [locationManger startMonitoringSignificantLocationChanges];
    [locationManger stopMonitoringSignificantLocationChanges];


导航
    // 设备是否支持heading航向(模拟器不支持)
    BOOL isCanHeading=[CLLocationManager headingAvailable];
    // 获取 最后更新的航向(readOnly)
    CLHeading *heading=locationManger.heading;
    // 开始/结束监测方向变化
    [locationManger startUpdatingHeading];
    [locationManger stopUpdatingHeading];


监测区域
    // 获取 是否支持监测指定区域的位置更新变换
    BOOL isCanMonitorRegion=[CLLocationManager isMonitoringAvailableForClass:nil];
    // 获取 最大的监测区域范围 (readOnly)
    CLLocationDistance distance=locationManger.maximumRegionMonitoringDistance;
    // 获取 所有监测的区域 (readOnly)
    NSSet<CLRegion *> regionMonSet=locationManger.monitoredRegions;
    // 获取 所有区域 (readOnly)
    NSSet<CLRegion *> regionSet=locationManger.rangedRegions;
    // 开始/结束监测区域变化
    [locationManger startMonitoringForRegion:[CLRegion new]];
    [locationManger stopMonitoringForRegion:[CLRegion new]];
    // 开始/结束监测指定区域的信号坐标
    [locationManger startRangingBeaconsInRegion:[CLBeaconRegion new]];
    [locationManger stopRangingBeaconsInRegion:[CLBeaconRegion new]];


延迟更新
    // 获取 是否延迟位置更新
    BOOL isDefre=[CLLocationManager deferredLocationUpdatesAvailable];
    // 设置 允许延迟更新
    [locationManger allowDeferredLocationUpdatesUntilTraveled:10 timeout:2];
    // 设置 不允许延迟更新位置
    [locationManger disallowDeferredLocationUpdates];

dele

    // <CLLocationManagerDelegate>
    [locationManger setDelegate:self];  

// 定位出现错误后调用
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{}

位置更新
// 调用startUpdatingLocation后,更新位置后会调用此方法
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{}
// 当暂停更新位置后调用
-(void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager{}
// 当恢复更新位置后调用
-(void)locationManagerDidResumeLocationUpdates:(CLLocationManager *)manager{}


导航
// 调用startUpdatingHeading后,更新方向后调用此方法
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading{}
// 在改变方向稳定之前是否显示校准视图
-(BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager{}


区域监测
// 当用户进入指定区域后调用
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{}
// 当用户离开指定区域后调用
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region{}
// 当检测指定区域失败后调用
-(void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error{}
// 调用startMonitoringForRegion:成功后调用
-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region{}
// 在监测区域状态改变后调用
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{}
// 当一个新的信号在指定区域出现时调用
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray<CLBeacon *> *)beacons inRegion:(CLBeaconRegion *)region{}
// 当指定区域的信号发生错误时调用
-(void)locationManager:(CLLocationManager *)manager rangingBeaconsDidFailForRegion:(CLBeaconRegion *)region withError:(NSError *)error{}
// 监测到之前访问过该位置时调用
-(void)locationManager:(CLLocationManager *)manager didVisit:(CLVisit *)visit{}

// 当位置权限改变后调用
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{}
// 停止延迟更新后调用
-(void)locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error{}

4.2 CLLocation

CLLocation 位置信息

    // 新建
    CLLocation *loction=[[CLLocation alloc]initWithLatitude:180 longitude:100];
    CLLocation *loction=[[CLLocation alloc]initWithCoordinate:CLLocationCoordinate2DMake(180, 80) altitude:100 horizontalAccuracy:1 verticalAccuracy:1 timestamp:[NSDate date]];
    CLLocation *loction=[[CLLocation alloc]initWithCoordinate:CLLocationCoordinate2DMake(100, 100) altitude:100 horizontalAccuracy:1 verticalAccuracy:1 course:1 speed:1 timestamp:[NSDate date]];
    

    CLLocation location=locationManger.location;   // 获取 最后更新的位置(readOnly)
    // 经纬度(readOnly)
    CLLocationCoordinate2D loct=loction.coordinate;
    // 海拔(readOnly)
    CLLocationDistance altitude=location.altitude;
    // 水平精度---容错半径(readOnly)
    CLLocationAccuracy hA=location.horizontalAccuracy;
    // 纵向精度---容错半径(readOnly)
    CLLocationAccuracy vA=loction.verticalAccuracy;
    // 设备的前进方向与正北的角度---0~359.9(readOnly)
    CLLocationDirection course=location.course;
    // 速度---m/s(readOnly)
    CLLocationSpeed speed=location.speed;
    // 最后更新位置被确定时的时间戳(readOnly)
    NSDate *date=location.timestamp;
    // 楼层数(readOnly)
    CLFloor floor=location.floor;
    // 两个位置之间的距离
    CLLocationDistance distan=[location distanceFromLocation:[CLLocation new]];


typedef struct {
    CLLocationDegrees latitude;    // 纬度
    CLLocationDegrees longitude;   // 经度
} CLLocationCoordinate2D;

4.3 CLGeocoder

CLGeocoder 编码

    CLGeocoder *geocoder=[CLGeocoder new];
    // 是否正在进行地理编码
    BOOL isGeoing=[geocoder isGeocoding];
    // 中止地理编码
    [geocoder cancelGeocode];
    
    // 坐标转地名
    [geocoder reverseGeocodeLocation:[CLLocation new] completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        //
    }];
    [geocoder reverseGeocodeLocation:[CLLocation new] preferredLocale:[NSLocale new] completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
    }];
    
    // 地名转坐标
    [geocoder geocodeAddressString:@"北京" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
    }];
    [geocoder geocodeAddressString:@"" inRegion:[CLRegion new] completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
    }];
    [geocoder geocodeAddressString:@"" inRegion:[CLRegion new] preferredLocale:[NSLocale new] completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
    }];
    [geocoder geocodeAddressDictionary:@{} completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
    }];
    
    
    [geocoder geocodePostalAddress:[CNPostalAddress new] completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
    }];
    [geocoder geocodePostalAddress:[CNPostalAddress new] preferredLocale:[NSLocale new] completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
    }];

4.4 CLHeading 导航

    // 获取 最后更新的航向(readOnly)
    CLHeading *heading=locationManger.heading;

    // 设备的朝向---0~359.9 0为北磁极(readOnly)
    CLLocationDirection magneticHeading=heading.magneticHeading;
    // 设备的真实朝向---0~359.9 0为北极(readOnly)
    CLLocationDirection trueHeading=heading.trueHeading;
    // 方向偏差(readOnly)
    CLLocationDirection headingAccuracy=heading.headingAccuracy;
    // x(readOnly)
    CLHeadingComponentValue x=heading.x;
    // y(readOnly)
    CLHeadingComponentValue y=heading.y;
    // z(readOnly)
    CLHeadingComponentValue z=heading.z;
    // 当前导航的时间戳(readOnly)
    NSDate *timestamp=heading.timestamp;

4.5 CLPlacemark

CLPlacemark 地理坐标信息
    CLPlacemark *placeMark=[[CLPlacemark alloc]initWithPlacemark:[CLPlacemark new]];
    // 位置(readOnly)
    CLLocation *loc=placeMark.location;
    // 区域(readOnly)
    CLRegion *region=placeMark.region;
    // 时区(readOnly)
    NSTimeZone *timeZone=placeMark.timeZone;
    // 详细信息dic(readOnly)
    NSDictionary *addressDic=placeMark.addressDictionary;
    
    // dic中
    //
    NSString *name=placeMark.name;
    // 街道
    NSString *tho=placeMark.thoroughfare;
    NSString *subTho=placeMark.subThoroughfare;
    // 城市
    NSString *locality=placeMark.locality;
    NSString *subLocality=placeMark.subLocality;
    NSString *ad=placeMark.administrativeArea;
    NSString *subAd=placeMark.subAdministrativeArea;
    NSString *posta=placeMark.postalCode;
    NSString *iso=placeMark.ISOcountryCode;
    // 国家
    NSString *country=placeMark.country;
    NSString *inland=placeMark.inlandWater;
    NSString *ocan=placeMark.ocean;
    NSArray *areaArr=placeMark.areasOfInterest;

4.6 导航相关

MKPlacemark
    // 地点信息类
    // MKPlacemark : CLPlacemark <MKAnnotation>
    MKPlacemark placeM=[[MKPlacemark alloc]initWithCoordinate:CLLocationCoordinate2DMake(36, 116) addressDictionary:@{}];
    // 国家编码(readOnly)
    NSString *countryCode=placeM.countryCode;


MKMapItem
    // 地点节点类
    // MKMapItem: NSObject
    // 根据placemark创建
    MKMapItem *mapItem=[[MKMapItem alloc]initWithPlacemark:placeM];
    // 根据当前位置创建
    MKMapItem *mapItem=[MKMapItem mapItemForCurrentLocation];
    // placemark地点信息(readOnly)
    MKPlacemark *placemark=mapItem.placemark;
    // 是否是当前位置
    BOOL isCurrentL=mapItem.isCurrentLocation;
    // 节点名称
    @property (nonatomic, copy) NSString *name;
    // 电话号码
    @property (nonatomic, copy) NSString *phoneNumber;
    // 网址
    @property (nonatomic, strong) NSURL *url;
    // 时区
    @property (nonatomic, copy, nullable) NSTimeZone *timeZone;


MKDirectionsRequest
    // 导航请求类(设置查询条件(出发/结束地址等)进行查询)
    @interface MKDirectionsRequest : NSObject
    // 出发节点
    - (MKMapItem *)source;
    - (void)setSource:(MKMapItem *)source;
    // 结束节点
    - (MKMapItem *)destination;
    - (void)setDestination:(MKMapItem *)destination;
    // 路线检索类型
    @property (nonatomic) MKDirectionsTransportType transportType;
    typedef NS_OPTIONS(NSUInteger, MKDirectionsTransportType) {
        MKDirectionsTransportTypeAutomobile     = 1 << 0,   // 适合驾车时导航
        MKDirectionsTransportTypeWalking        = 1 << 1,   // 适合步行时导航
        MKDirectionsTransportTypeAny            = 0x0FFFFFFF// 任何情况(默认)
    };
    // 是否搜索多条路线
    @property (nonatomic) BOOL requestsAlternateRoutes;
    // 出发日期 
    @property (nonatomic, copy, nullable) NSDate *departureDate;
    // 结束日期
    @property (nonatomic, copy, nullable) NSDate *arrivalDate;
    @end



MKDirections
    // 计算路线数据类
    @interface MKDirections : NSObject
    // 创建
    - (instancetype)initWithRequest:(MKDirectionsRequest *)request;
    // 开始计算获取线路信息
    - (void)calculateDirectionsWithCompletionHandler:(MKDirectionsHandler)completionHandler;
    // 开始计算时间信息
    - (void)calculateETAWithCompletionHandler:(MKETAHandler)completionHandler;
    // 取消
    - (void)cancel;
    // 是否正在计算
    @property (nonatomic, readonly, getter=isCalculating) BOOL calculating;
    @end


MKETAResponse
    // 时间信息结果类
    @interface MKETAResponse : NSObject
    // 起点
    @property (nonatomic, readonly) MKMapItem *source;
    // 终点
    @property (nonatomic, readonly) MKMapItem *destination;
    // 耗时
    @property (nonatomic, readonly) NSTimeInterval expectedTravelTime;
    //
    @property (nonatomic, readonly) CLLocationDistance distance;
    //
    @property (nonatomic, readonly) NSDate *expectedArrivalDate;
    //
    @property (nonatomic, readonly) NSDate *expectedDepartureDate;
    //
    @property (nonatomic, readonly) MKDirectionsTransportType transportType ;
    @end


MKDirectionsResponse
    // 线路信息结果类
    @interface MKDirectionsResponse : NSObject
    // 起点
    @property (nonatomic, readonly) MKMapItem *source;
    // 终点
    @property (nonatomic, readonly) MKMapItem *destination;
    // 线路规划数组(存放所有的线路)
    @property (nonatomic, readonly) NSArray *routes;
    @end


MKRoute
    // 整条线路类
    @interface MKRoute : NSObject
    // 线路名
    @property (nonatomic, readonly) NSString *name;
    // 线路注意事项
    @property (nonatomic, readonly) NSArray *advisoryNotices;
    // 线路距离
    @property (nonatomic, readonly) CLLocationDistance distance;
    // 线路耗时
    @property (nonatomic, readonly) NSTimeInterval expectedTravelTime;
    // 线路检索类型
    @property (nonatomic, readonly) MKDirectionsTransportType transportType;
    // 线路覆盖物
    @property (nonatomic, readonly) MKPolyline *polyline;
    // 线路详情数组(存放所有部分线路)
    @property (nonatomic, readonly) NSArray *steps;
    @end



MKRouteStep  每一条线路信息
    @interface MKRouteStep : NSObject
    // 线路节点信息
    @property (nonatomic, readonly) NSString *instructions;
    // 线路节点注意事项
    @property (nonatomic, readonly) NSString *notice;
    // 线路覆盖物
    @property (nonatomic, readonly) MKPolyline *polyline;
    // 线路距离
    @property (nonatomic, readonly) CLLocationDistance distance;
    // 线路导航类型
    @property (nonatomic, readonly) MKDirectionsTransportType transportType;
    @end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容

  • http://www.cnblogs.com/kenshincui/p/4125570.html 摘要: 现在很多...
    大崔老师阅读 3,278评论 1 2
  • 出自http://my.oschina.net/are1OfBlog/blog/420034 摘要 现在很多社交、...
    JJO阅读 4,124评论 4 19
  • 作者:柳骏原文地址:http://www.ios520junge.com/ 初学地图时,觉得地图是个很高深的玩意儿...
    行走的苹果哥阅读 1,319评论 0 4
  • *初学地图时,觉得地图是个很高深的玩意儿,导航、定位、检索这得运用多少算法和核心动画的知识点啊,于是一直排斥 * ...
    柳骏阅读 3,714评论 11 22
  • 水调歌头·黄州快哉亭赠张偓佺 宋 · 苏轼 落日绣帘卷,亭下水连空。知君为我,新作窗户湿青红。长记平山堂上,欹枕江...
    于斯用心阅读 206评论 0 1