iOS學習筆記19-地圖(一)定位CoreLocation
一、定位介紹
現在很多社交、電商、團購應用都引入了地圖和定位功能,似乎地圖功能不再是地圖應用和導航應用所特有的。的確,有了地圖和定位功能確實讓我們的生活更加豐富多彩,極大的改變了我們的生活。要實現地圖、導航功能,往往需要先熟悉定位功能。
在iOS中通過
CoreLocation
架構進行定位操作。
CoreLocation
自身可以單獨使用,和地圖開發架構MapKit
完全是獨立的,但是往往地圖開發要配合定位架構使用。
CoreLocation
可以實現的功能:定位功能地理編碼與逆地理編碼
二、定位核心類
定位是一個很常用的功能,如一些地圖軟體開啟之後如果使用者允許軟體定位的話,那麼開啟軟體後就會自動鎖定到當前位置,如果使用者手機移動那麼當前位置也會跟隨著變化。要實現這個功能需要使用CoreLoaction
中CLLocationManager
類,下面是這個類的使用說明:
1. 類方法:
+ (BOOL)locationServicesEnabled;/* 返回使用者是否啟用定位服務 */+ (CLAuthorizationStatus)authorizationStatus;/* 定位服務授權狀態,返回枚舉類型 */typedefNS_ENUM(int,CLAuthorizationStatus){ kCLAuthorizationStatusNotDetermined = 0, /* 使用者尚未決定是否啟用定位服務 */ kCLAuthorizationStatusRestricted, /* 沒有獲得使用者授權 */ kCLAuthorizationStatusDenied, /* 使用者禁止使用定位或者定位服務處於關閉狀態 */ kCLAuthorizationStatusAuthorizedAlways, /*前台、後台定位授權 */ kCLAuthorizationStatusAuthorizedWhenInUse, /* 前台定位授權 */};
2. 對象屬性:定位精度
desiredAccuracy
:
枚舉類型:
位置資訊更新最小距離
distanceFilter
:
浮點數,預設為
kCLDistanceFilterNone
,表示不進行距離限制3. 對象方法:
#pragma mark - 定位追蹤-(void)startUpdatingLocation;/* 開始定位追蹤 */-(void)stopUpdatingLocation;/* 停止定位追蹤 */#pragma mark - 導航追蹤-(void)startUpdatingHeading;/* 開始導航方向追蹤 */-(void)stopUpdatingHeading;/* 停止導航方向追蹤 */#pragma mark - 地區定位追蹤-(void)startMonitoringForRegion:(CLRegion *)region;/* 開始對某個地區進行定位追蹤 */-(void)stopMonitoringForRegion:(CLRegion *)region;/* 停止對某個地區進行定位追蹤 */#pragma mark - 授權請求-(void)requestWhenInUseAuthorization;/* 請求獲得應用前台定位授權 */-(void)requestAlwaysAuthorization;/* 請求獲得應用前後台定位授權 */
4. 常用代理方法
CLLocationManagerDelegate
:
/* 位置發生改變後調用,第一次定位也會調用 */-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;/* 導航方向發生變化後調用 */-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading;/* 進入某個地區後調用 */-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region;/* 走出某個地區後調用 */-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region;/* 當使用者授權狀態發生變化時調用 */-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status;
三、定位簡單使用先要在項目匯入CoreLocation架構,然後再匯入標頭檔:
#import
iOS版本不同,使用也有一些區別,主要區分為:iOS8.0之前的定位使用iOS8.0之後的定位使用1. iOS8.0之前的定位使用:1.1 前台定位:
- (void)viewDidLoad{ [super viewDidLoad]; if (![CLLocationManager locationServicesEnabled]) { NSLog(@"定位服務當前可能尚未開啟,請設定開啟!"); return; } [self initLocationManager]; //調用方法,開始更新使用者位置資訊 [self.locationM startUpdatingLocation];}//建立CLLocationManager並啟動定位- (void)initLocationManager{ //建立CLLocationManager對象並設定代理 self.locationM = [[CLLocationManager alloc] init]; self.locationM.delegate = self; //設定定位精度和位置更新最小距離 self.locationM.distanceFilter = 100; self.locationM.desiredAccuracy = kCLLocationAccuracyBest;}//在對應的代理方法中擷取位置資訊- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{ CLLocation *location = [locations firstObject];//取出第一個位置 /* 使用位置前, 務必判斷當前擷取的位置是否有效 如果水平精確度小於零, 代表雖然可以擷取位置對象, 但是資料錯誤, 不可用 */ if (location.horizontalAccuracy < 0) return; CLLocationCoordinate2D coordinate = location.coordinate;//位置座標 CGFloat longitude = coordinate.longitude;//經度 CGFloat latitude = coordinate.latitude;//緯度 CGFloat altitude = location.altitude;//海拔 CGFloat course = location.course;//方向 CGFloat speed = location.speed;//速度 NSLog(@"經度:%f,緯度:%f",longitude,latitude); NSLog(@"海拔:%f,方向:%f,速度:%f",altitude,course,speed); //如果不需要即時定位,使用完即使關閉定位服務 [self.locationM stopUpdatingLocation]; }
定位頻率和定位精度並不是越精確越好,需要視實際情況而定,因為越精確越耗效能,也就越費電。定位成功後會根據設定情況頻繁調用
locationManager:didUpdateLocations:
方法每個元素一個
CLLocation
代表地理位置資訊,之所以返回數組是因為有些時候一個位置點可能包含多個位置。使用完定位服務後,如果不需要即時監控應該立即關閉定位服務,以節省資源。除了提供定位功能,還可以調用
startMonitoringForRegion:
方法對指定地區進行監控。1.2 後台定位:
在前台的基礎上,勾選後台模式Location updates
2. iOS8之後的定位使用iOS8開始,需要請求定位授權:前台授權:
在Info.plist檔案中配置
NSLocationWhenInUseUsageDescription
為
YES
前後台授權:
在Info.plist檔案中配置
NSLocationAlwaysUsageDescription
為
YES
- (void)viewDidLoad{ [super viewDidLoad]; if (![CLLocationManager locationServicesEnabled]) { NSLog(@"定位服務當前可能尚未開啟,請設定開啟!"); return; } [self initLocationManager]; //如果沒有授權,則請求使用者授權 CLAuthorizationStatus status = [CLLocationManager authorizationStatus]; if (status == kCLAuthorizationStatusNotDetermined){ //請求前台定位授權 //[self.locationM requestWhenInUseAuthorization]; //請求前後台定位授權 [self.locationM requestAlwaysAuthorization]; }}//建立CLLocationManager並啟動定位- (void)initLocationManager{ //建立CLLocationManager對象並設定代理 self.locationM = [[CLLocationManager alloc] init]; self.locationM.delegate = self; //設定定位精度和位置更新最小距離 self.locationM.distanceFilter = 100; self.locationM.desiredAccuracy = kCLLocationAccuracyBest;}// 當使用者授權狀態發生變化時調用- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{ switch (status) { case kCLAuthorizationStatusNotDetermined://使用者還未決定 { NSLog(@"使用者還未決定"); break; } case kCLAuthorizationStatusRestricted://訪問受限 { NSLog(@"訪問受限"); break; } case kCLAuthorizationStatusDenied://定位關閉時或使用者APP授權為永不授權時調用 { NSLog(@"定位關閉或者使用者未授權"); break; } case kCLAuthorizationStatusAuthorizedAlways://擷取前後台定位授權 { NSLog(@"擷取前後台定位授權"); [self.locationM startUpdatingLocation]; break; } case kCLAuthorizationStatusAuthorizedWhenInUse://獲得前台定位授權 { NSLog(@"獲得前台定位授權"); [self.locationM startUpdatingLocation]; break; } default:break; }}//在對應的代理方法中擷取位置資訊- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{ CLLocation *location = [locations firstObject];//取出第一個位置 /* 使用位置前, 務必判斷當前擷取的位置是否有效 如果水平精確度小於零, 代表雖然可以擷取位置對象, 但是資料錯誤, 不可用 */ if (location.horizontalAccuracy < 0) return; CLLocationCoordinate2D coordinate = location.coordinate;//位置座標 CGFloat longitude = coordinate.longitude;//經度 CGFloat latitude = coordinate.latitude;//緯度 CGFloat altitude = location.altitude;//海拔 CGFloat course = location.course;//方向 CGFloat speed = location.speed;//速度 NSLog(@"經度:%f,緯度:%f",longitude,latitude); NSLog(@"海拔:%f,方向:%f,速度:%f",altitude,course,speed); //如果不需要即時定位,使用完即使關閉定位服務 [self.locationM stopUpdatingLocation];}
四、地理編碼
定位服務中還包含CLGeocoder
類,用於處理地理編碼和逆地理編碼功能。
* 地理編碼:根據給定的位置(通常是地名)確定地理座標(經、緯度)。
【位置 -> 地理座標】
* 逆地理編碼:可以根據地理座標(經、緯度)確定位置資訊(街道、門牌等)。
【地理座標 -> 位置】
- (void)viewDidLoad { [super viewDidLoad]; self.geocoder = [[CLGeocoder alloc] init]; [self getCoordinateByAddress:@"北京"]; [self getAddressByLatitude:39.54 longitude:116.28];}#pragma mark 根據地名確定地理座標-(void)getCoordinateByAddress:(NSString *)address{ //地理編碼 [self.geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) { //取得第一個地標,地標中儲存了詳細的地址資訊,注意:一個地名可能搜尋出多個地址 CLPlacemark *placemark = [placemarks firstObject]; CLLocation *location = placemark.location;//位置 CLRegion *region = placemark.region;//地區 NSDictionary *addressDic = placemark.addressDictionary;//詳細地址資訊字典 NSLog(@"位置:%@,地區:%@,詳細資料:%@",location,region,addressDic); }];}#pragma mark 根據座標取得地名-(void)getAddressByLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude{ //反地理編碼 CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude]; [self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) { CLPlacemark *placemark = [placemarks firstObject]; NSLog(@"詳細資料:%@",placemark.addressDictionary); }];}
地標類
CLPlacemark
還包含以下資訊:
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; //關聯的或利益相關的地標
下一節我會寫地圖類MapKit的相關筆記,敬請期待吧!有什麼問題可以在下方評論區提出,O(∩_∩)O哈!