iOS開發 - 地圖與定位

定位

定位功能
  • 定位主要用于獲取用戶當前地理位置信息。
  • 常用的定位技術:
    GPS定位(全球定位系統:最精準的定位方式);
    Skyhook Wi-Fi定位(Wi-Fi路由器);
    因特網提供商定位技術(提供商中心站);
    多種定位方法混合使用;
  • Core Location是iOS中實現定位功能的框架,提供了大量接口對定位功能進行配置及獲取地理位置數據。
  • 使用Core Location需要導入框架:CoreLocation.framework。
  • CoreLocation提供了CLLocationManager類來對定位功能進行管理,包括定位功能的配置、開始、停止定位等。
  • CoreLocation也提供了CLLocationManagerDelegate委托協議來處理CLLocationManager在定位過程中觸發的事件。
CLLocationManager 工作流程
926110847675.png
  • CLLocationManager 定位授權
    iOS8以后,如果需要使用定位功能,需請求用戶授權,在首次運行時會彈框提示,方法如下:
// 1、請求在使用期間授權定位,需在Info.plist文件中加入字段:NSLocationWhenInUseUsageDescription
- (void)requestWhenInUseAuthorization;

// 2、請求總是授權定位,需在Info.plist文件中加入字段:NSLocationAlwaysUsageDescription
- (void)requestAlwaysAuthorization;
  • CLLocationManager 常用屬性
    delegate:設置代理

    distanceFilter:設置定位頻率,每隔多少米定位一次

    desiredAccuracy:設置定位精度(kCLLocationAccuracy)
  • CLLocationManager 常用方法

  • 類方法

// 1、是否啟用定位服務,通常如果用戶沒有啟用定位服務可以提示用戶打開定位服務 + (BOOL)locationServicesEnabled; // 2、定位服務授權狀態,返回枚舉類型: + (CLAuthorizationStatus)authorizationStatus;
  • 實例化方法
// 1、開始定位追蹤
- (void)startUpdatingLocation;
// 2、停止定位追蹤
- (void)stopUpdatingLocation;
// 3、開始導航方向追蹤
- (void)startUpdatingHeading;
// 4、停止導航方向追蹤
- (void)stopUpdatingHeading;
  • 代理方法
// 1、定位失敗 - (void)locationManager:(CLLocationManager *)manager
    didFailWithError:(NSError *)error;

// 2、位置發生改變后執行(第一次定位到某個位置之后也會執行)
- (void)locationManager:(CLLocationManager *)manager
  didUpdateLocations:(NSArray *)locations;

// 3、導航方向發生變化后執行
- (void)locationManager:(CLLocationManager *)manager
  didUpdateHeading:(CLHeading *)newHeading;

// 4、進入某個區域之后執行
- (void)locationManager:(CLLocationManager *)manager
  didEnterRegion:(CLRegion *)region;

// 5、走出某個區域之后執行
- (void)locationManager:(CLLocationManager *)manager
  didExitRegion:(CLRegion *)region;
CLLocationManager 定位代碼示例
#import "ViewController.h"
// 定位框架
#import <CoreLocation/CoreLocation.h>

#define NSLOG(OBJECT)  NSLog(@"%@", OBJECT)

@interfaceViewController () <CLLocationManagerDelegate>
{
    CLLocationManager *_locationManager; /**< 定位服務 */
}

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 1、判斷設備是否開啟定位服務
    if (![CLLocationManager locationServicesEnabled]) {
        // 彈框提示
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"溫馨提示" message:@"您的設備暫未開啟定位服務!" preferredStyle:UIAlertControllerStyleAlert];
        [alertController addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:nil]];
        [self presentViewController:alertController animated:YES completion:nil];
        
        return;
    }
    // 2、初始化定位服務
    _locationManager = [[CLLocationManager alloc] init];
    
    // 3、請求定位授權
    // 請求在使用期間授權(彈框提示用戶是否允許在使用期間定位),需添加NSLocationWhenInUseUsageDescription到info.plist
    [_locationManager requestWhenInUseAuthorization];
    // 請求在后臺定位授權(彈框提示用戶是否允許不在使用App時仍然定位),需添加NSLocationAlwaysUsageDescription添加key到info.plist
    [_locationManager requestAlwaysAuthorization];
    
    // 4、設置定位精度
    _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    
    // 5、設置定位頻率,每隔多少米定位一次
    _locationManager.distanceFilter = 10.0;
    
    // 6、設置代理 _locationManager.delegate = self;
    
    // 7、開始定位
    // 注意:開始定位比較耗電,不需要定位的時候最好調用 [stopUpdatingLocation] 結束定位。
    [_locationManager startUpdatingLocation];
}


#pragma mark - CLLocationManagerDelegate methods

// 定位失敗
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    
    NSLOG(error.localizedDescription);
}

// 位置更新
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
    // 獲取最新定位
    CLLocation *location = locations.lastObject;
    
    // 打印位置信息
    NSLog(@"精度:%.2f, 緯度:%.2f", location.coordinate.latitude, location.coordinate.longitude);
    // 停止定位
    [_locationManager stopUpdatingLocation];
}

@end
  • 注意:
1、定位頻率和定位精度并不應當越精確越好,需要視實際情況而定,因為越精確越耗性能,也就越費電。
2、定位成功后會根據設置情況頻繁調用didUpdateLocations:方法,這個方法返回一組地理位置對象數組,每個元素是一個CLLocation,代表地理位置信息(包含經度、緯度、海報、行走速度等信息),之所以返回數組是因為有些時候一個位置點可能包含多個位置。
3、使用完定位服務后如果不需要實時監控應該立即關閉定位服務以節省資源。
4、除了提供定位功能,CLLocationManager還可以調用startMonitoringForRegion:方法對指定區域進行監控。

地理編碼

除了提供位置跟蹤功能之外,在定位服務中還包含CLGeocoder 類用于處理地理編碼和逆地理編碼(又叫反地理編碼)功能。

地理編碼:根據給定的位置(通常是地名)確定地理坐標(經、緯度)。

逆地理編碼:可以根據地理坐標(經、緯度)確定位置信息(街道、門牌等)。
  • 地理編碼方法
// 1、地理編碼 
- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;

// 2、逆地理編碼
- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;

  • 地理編碼示例
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>

@interface ViewController ()
{
    CLGeocoder *_geocoder;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _geocoder = [[CLGeocoder alloc] init];
    
    [self getCoordinateByAddress:@"成都"];
    
    [self getAddressByLatitude:39.54 longitude:116.28];
    
}

#pragma mark - 根據地名確定地理坐標 

- (void)getCoordinateByAddress:(NSString *)address {
    // 地里編碼
    [_geocoder geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        // 取得第一個地標,地標中存儲了詳細的地址信息
        // 注意:一個地名可能搜索出多個地址
        CLPlacemark *placemark   = placemarks.firstObject;
        // 位置 CLLocation *location     = placemark.location;
        // 區域 CLRegion *region         = placemark.region;
        // 詳細地址信息字典
        NSDictionary *addressDic = placemark.addressDictionary;
        NSLog(@"\n位置:%@\n區域:%@\n詳細信息:%@\n", location, region, addressDic);
        /*
         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;//關聯的或利益相關的地標
         */
    }];
}

#pragma mark - 根據坐標取得地名 

- (void)getAddressByLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude {
    // 反地理編碼
    CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
    
    [_geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        if (error) {
            NSLog(@"%@", error.localizedDescription);
        }else {
            CLPlacemark *placemark=[placemarks firstObject];
            NSLog(@"詳細信息:%@",placemark.addressDictionary);
        }
    }];
}

@end
  • 注意:地理編碼和逆地理編碼不可同時執行;

地圖

  • iOS從6.0開始地圖數據不再由谷歌驅動,而是改用自家地圖,當然在國內它的數據是由高德地圖提供的。這樣一來,如果在iOS6.0之前進行地圖開發的話使用方法會有所不同,基于目前的情況其實使用iOS6.0之前版本的系統基本已經寥寥無幾了,所有在接下來的內容中不會再針對iOS5及之前版本的地圖開發進行介紹。

  • 在iOS中進行地圖開發主要有兩種方式,一種是直接利用MapKit框架進行地圖開發,利用這種方式可以對地圖進行精準的控制;另一種方式是直接調用蘋果官方自帶的地圖應用,主要用于一些簡單的地圖應用(例如:進行導航覆蓋物填充等),無法進行精確的控制。當然,本節重點內容還是前者,后面的內容也會稍加提示。

  • Map Kit框架中 MKMapView類 提供了系統自帶的地圖界面效果,配合Core Location的使用可以展示多樣化的信息。

  • 使用Map Kit需要導入框架:MapKit.framework

MKMapView 常用屬性
  • showsUserLocation:設置是否顯示用戶位置

  • userTrackingMode:設置跟蹤類型,枚舉類型

    MKUserTrackingModeNone:不進行用戶位置跟蹤

    MKUserTrackingModeFollow:跟蹤用戶位置

    MKUserTrackingModeFollowWithHeading:跟蹤用戶位置并且跟蹤用戶前進方向
  • showsTraffic:設置是否顯示交通(ios9新特性)

  • showsScale:設置是否顯示比例(ios9新特性)

  • showsCompass:設置是否顯示指南針(ios9新特性)

  • userLocation:用戶位置信息,只讀屬性

  • userLocation.title:設置用戶位置信息標題

  • userLocation.subtitle:設置用戶位置信息子標題

  • annotations:當前地圖中的所有大頭針,只讀屬性

  • mapType:設置地圖類型

    MKMapTypeStandard:標準地圖,一般情況下使用此地圖即可滿足

    MKMapTypeSatellite:衛星地圖

    MKMapTypeHybrid:混合地圖,加載最慢比較消耗資源

    MKMapTypeSatelliteFlyover:iOS9新特性,衛星地圖,支持城市觀光

    MKMapTypeHybridFlyover:iOS9新特性,混合地圖,支持城市觀光
MKMapView 常用方法
  • 初始化方法
- (instancetype)initWithFrame:(CGRect)frame;
  • 實例化方法
// 1、添加大頭針,對應的有添加大頭針數組
 - (void)addAnnotation:(id <MKAnnotation>)annotation;

// 2、刪除大頭針,對應的有刪除大頭針數組 
- (void)removeAnnotation:(id <MKAnnotation>)annotation;

// 3、設置地圖顯示區域,用于控制當前屏幕顯示地圖范圍 
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated; 

// 4、設置地圖中心點位置 
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated;

 // 5、將地理坐標(經緯度)轉化為數學坐標(UIKit坐標)CGPoint 
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(nullable UIView *)view; 

// 6、將數學坐標CGPoint轉換為地理坐標 
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(nullable UIView *)view; 

// 7、從緩存池中取出大頭針,類似于UITableView中取出UITableViewCell,為了進行性能優化而設計 
- (nullable MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier; 

// 8、選中指定的大頭針
- (void)selectAnnotation:(id <MKAnnotation>)annotation animated:(BOOL)animated; 

// 9、取消選中指定的大頭針
- (void)deselectAnnotation:(nullable id <MKAnnotation>)annotation animated:(BOOL)animated;
  • 代理方法
// 1、用戶位置發生改變時觸發(第一次定位到用戶位置也會觸發該方法) 
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation; 

// 2、地圖加載完成后觸發 
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView; 

// 3、顯示大頭針時觸發,返回大頭針視圖,通常自定義大頭針可以通過此方法進行 
- (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation; 

// 4、點擊選中某個大頭針時觸發 
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view; 

// 5、取消選中大頭針時觸發 
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view; 

// 6、渲染地圖覆蓋物時觸發 
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay
用戶位置跟蹤
  • 在很多帶有地圖的應用中默認打開地圖都會顯示用戶當前位置,同時將當前位置標記出來放到屏幕中點方便用戶對周圍情況進行查看。如果在iOS6或者iOS7中實現這個功能只需要添加地圖控件、設置用戶跟蹤模式、在didUpdateUserLocation:代理方法中設置地圖中心區域及顯示范圍。但是在iOS8中用法稍有不同:

      由于在地圖中進行用戶位置跟蹤需要使用定位功能,而定位功能在iOS8中設計發生了變化,因此必須按照前面定位章節中提到的內容進行配置和請求。
    
      iOS8中不需要進行中心點的指定,默認會將當前位置設置中心點并自動設置顯示區域范圍。
    
  • 了解以上兩點,要進行用戶位置跟蹤其實就相當簡單了,值得一提的是didUpdateUserLocation:這個代理方法。這個方法只有在定位到當前位置之后就會調用,以后每當用戶位置發生改變就會觸發,調用頻率相當頻繁。

大頭針
  • 在iOS開發中經常會標記某個位置,需要使用地圖標注,也就是大家俗稱的“大頭針”。只要一個NSObject類實現MKAnnotation協議就可以作為一個大頭針,通常會重寫協議中coordinate(標記位置)、title(標題)、subtitle(子標題)三個屬性,然后在程序中創建大頭針對象并調用addAnnotation:方法添加大頭針即可(之所以iOS沒有定義一個基類實現這個協議供開發者使用,多數原因應該是MKAnnotation是一個模型對象,對于多數應用模型會稍有不同,例如后面的內容中會給大頭針模型對象添加其他屬性)。下面代碼示例中,實現通過長按手勢,添加大頭針邏輯。
926141006362.png
- (void)respondsToGesture:(UILongPressGestureRecognizer *)gesture { // 當長按手勢開始時,添加一個標注數據源if (gesture.state == UIGestureRecognizerStateBegan) { // 獲取用戶長按手勢在地圖上的點CGPoint point = [gesture locationInView:self.mapView]; // 將地圖上的點轉化為經緯度 CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView]; // 創建一個標注數據源,這里使用系統標注數據源:MKPointAnnotation,如果要自定義,必須遵守<MKAnnotation>協議 MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init]; // 配置標注數據源 annotation.coordinate = coordinate;
        annotation.title = @"標注位置";
        annotation.subtitle = [NSString stringWithFormat:@"經度:%.2f, 緯度:%.2f", coordinate.longitude, coordinate.latitude]; // 在地圖上添加標注 [self.mapView addAnnotation:annotation];
    }
}
  • MKAnnotationView 標注視圖
    在一些應用中系統默認的大頭針樣式可能無法滿足實際的需求,此時就需要修改大頭針視圖默認樣式。根據前面MapKit的代理方法不難發現viewForAnnotation:方法可以返回一個大頭針視圖,只要實現這個方法并在這個方法中定義一個大頭針視MKAnnotationView對象并設置相關屬性就可以改變默認大頭針的樣式

MKPinAnnotationView
MKPinAnnotationView為MKAnnotationView子類,其特有屬性如下:

    pinTintColor:設置大頭針前景色(iOS9新特性)

    animatesDrop:設置大頭針凋零效果
  • MKAnnotationView 常用屬性
    image:設置大頭針圖片
    selected:是否被選中狀態
    annotation:大頭針模型信息,包括標題、子標題、地理位置
    calloutOffset:點擊大頭針時彈出詳情信息視圖的偏移量
    leftCalloutAccessoryView:彈出詳情左側視圖
    rightCalloutAccessoryView:彈出詳情右側視圖
    canShowCallout:點擊大頭針是否顯示標題、子標題內容等,注意如果在viewForAnnotation:方法中重新定義大頭針默認情況是無法交互的,需要設其值為true。
  • 注意:
1、這個代理方法的調用時機:每當有大頭針顯示到系統可視界面中時就會調用此方法返回一個大頭針視圖放到界面中,同時當前系統位置標注(也就是地圖中藍色的位置點)也是一個大頭針,也會調用此方法,因此處理大頭針視圖時需要區別對待。
    2、類似于UITableView的代理方法,此方法調用頻繁,開發過程中需要重復利用MapKit的緩存池將大頭針視圖緩存起來重復利用。
    3、自定義大頭針默認情況下不允許交互,如果交互需要設置canShowCallout = true。
    4、如果代理方法返回nil則會使用默認大頭針視圖,需要根據情況設置。
  • 下面例子進行了標注視圖的自定義,這里設置了大頭針的彈出視圖、大頭針顏色以及偏移量等信息。

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    // MKPinAnnotationView:MKAnnotationView子類,可設置大頭針顏色pinTintColor(iOS9)
    // 由于當前位置的標注也是一個大頭針,所以此時需要判斷,此代理方法返回nil使用默認大頭針視圖
    if ([annotation isKindOfClass:[MKUserLocation class]]) {
        return nil;
        
    }
    static NSString * kMKPinAnnotationViewIdentifier = @"identifier";
    // 大頭針重用
    MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:kMKPinAnnotationViewIdentifier];
    if (!annotationView) {
        // 如果緩存池中不存在則新建
        annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:kMKPinAnnotationViewIdentifier];
    }
    // 修改大頭針視圖
    // 重新設置此類大頭針視圖的大頭針模型(因為有可能是從緩存池中取出來的,位置是放到緩存池時的位置)
    annotationView.annotation = annotation;
    // 設置大頭針圖片
    annotationView.image = [UIImage imageNamed:@"pin"];
    // 設置大頭針凋零效果
    annotationView.animatesDrop = YES;
    // 允許用戶交互點擊(彈框顯示標注詳情)
    annotationView.canShowCallout = YES;
    // 定義詳情視圖偏移量
    annotationView.calloutOffset = CGPointMake(0, 1);
    // 設置大頭針顏色
    annotationView.pinTintColor = [UIColor blueColor];
    // 自定義大頭針詳情右側視圖
    UIButton *navigationBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    navigationBtn.bounds = CGRectMake(0, 0, 100, 60);
    navigationBtn.backgroundColor = [UIColor grayColor];
    [navigationBtn setTitle:@"導航" forState:UIControlStateNormal];
    annotationView.rightCalloutAccessoryView = navigationBtn;
    
    return annotationView;
}

導航

  • 在自定義標注視圖上添加導航按鈕(這里需說明:如果添加在標注視圖上的控件繼承于UIControl,無需添加事件),在點擊導航按鈕時會自動觸發calloutAccessoryControlTapped:方法,如下將實現地圖導航路線繪制關鍵代碼。

  • 效果展示

926181326921.gif
  • 代碼示例
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
    // 導航
    // 異常處理,如果標注數據源標題為空,則直接retun。
    if ([view.annotation.title isKindOfClass:[NSNull class]]) {
        return;
        
    }
    // 創建兩個PlaceMark
    // MKPlacemark,定位框架中地標類,封裝了詳細的地理信息
    MKPlacemark *currentPlaceMark = [[MKPlacemark alloc] initWithCoordinate:mapView.userLocation.coordinate addressDictionary:nil];
    MKPlacemark *destinationPlaceMark = [[MKPlacemark alloc] initWithCoordinate:((MKPointAnnotation *)view.annotation).coordinate addressDictionary:nil];
    // 創建兩個MapItem
    MKMapItem *currentItem = [[MKMapItem alloc] initWithPlacemark:currentPlaceMark];
    MKMapItem *destinationItem = [[MKMapItem alloc] initWithPlacemark:destinationPlaceMark];
    // 創建導航請求
    MKDirectionsRequest *directionRequest = [[MKDirectionsRequest alloc] init];
    // 配置導航請求
    // 1、起點
    directionRequest.source = currentItem;
    // 2、終點
    directionRequest.destination = destinationItem;
    // 發送導航請求
    MKDirections *derections = [[MKDirections alloc] initWithRequest:directionRequest];
    // 獲取導航路線
    [derections calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
        // 添加一條路線(這里不會顯示,需要渲染路線)
        // MKRoute  路徑信息
        // polyLine 路線
        [_mapView addOverlay:((MKRoute *)response.routes[0]).polyline];
        
    }];
    
    // 設置交通類型
    directionRequest.transportType = MKDirectionsTransportTypeAutomobile;
    // 計算被請求的交通時間信息
    [directions calculateETAWithCompletionHandler:^(MKETAResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"預計進行時間:%.2f", response.expectedTravelTime);
    }];
    // 值得一提的是,即使實現了上述邏輯,導航路線也并不會被顯示出來,此時需要實現如下方法,對路線進行渲染。
}

// 路線渲染
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
    // 初始化路線渲染器
    MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
    // 設置路線寬度
    renderer.lineWidth = 2.0;
    // 設置路線顏色
    renderer.strokeColor = [UIColor redColor];
    return renderer;
}

系統自帶地圖導航

  • 要使用地圖導航功能在自帶地圖應用中相當簡單,只要設置參數配置導航模式即可。
  • 效果展示
926181116920.gif
  • 代碼示例

#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

@interface ViewController ()
{
    CLGeocoder *_geocoder;
}
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _geocoder=[[CLGeocoder alloc]init];
    
    [self startNavigation];
}

- (void)startNavigation {
    //根據“成都市”地理編碼
    [_geocoder geocodeAddressString:@"成都市" completionHandler:^(NSArray *placemarks, NSError *error) {
        //獲取第一個地標
        CLPlacemark *clPlacemark1 = [placemarks firstObject];
        
        MKPlacemark *mkPlacemark1 = [[MKPlacemark alloc]initWithPlacemark:clPlacemark1];
        //注意地理編碼一次只能定位到一個位置,不能同時定位,所在放到第一個位置定位完成回調函數中再次定位
        [_geocoder geocodeAddressString:@"重慶市" completionHandler:^(NSArray *placemarks, NSError *error) {
            // 獲取第一個地標
            CLPlacemark *clPlacemark2 = [placemarks firstObject];
            
            MKPlacemark *mkPlacemark2 = [[MKPlacemark alloc]initWithPlacemark:clPlacemark2];
            NSDictionary *options = @{MKLaunchOptionsMapTypeKey : @(MKMapTypeStandard),
                                      MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving};
            // MKMapItem *mapItem1 =[MKMapItem mapItemForCurrentLocation];
            //當前位置
            MKMapItem *mapItem1=[[MKMapItem alloc]initWithPlacemark:mkPlacemark1];
            
            MKMapItem *mapItem2=[[MKMapItem alloc]initWithPlacemark:mkPlacemark2];
            // 打開導航地圖
            [MKMapItem openMapsWithItems:@[mapItem1, mapItem2] launchOptions:options];
            
        }];
    }];
}
@end
特別說明
  • 由于定位和地圖框架中用到了諸多類,有些初學者容易混淆,下面簡單對比一下。
    CLLocation:用于表示位置信息,包含地理坐標、海拔等信息,包含在CoreLoaction框架中。

    MKUserLocation:一個特殊的大頭針,表示用戶當前位置。

    CLPlacemark:定位框架中地標類,封裝了詳細的地理信息。

    MKPlacemark:類似于CLPlacemark,只是它在MapKit框架中,可以根據CLPlacemark創建MKPlacemark。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容