現在很多社交、電商、團購應用都引入了地圖和定位功能,似乎地圖功能不再是地圖應用和導航應用所特有的。的確,有了地圖和定位功能確實讓我們的生活更加豐富多彩,極大的改變了我們的生活方式。要實現地圖、導航功能,往往需要先熟悉定位功能。
CoreLocation
框架進行定位操作。
CoreLocation
自身可以單獨使用,和地圖開發框架MapKit
完全是獨立的,但是往往地圖開發要配合定位框架使用。
CoreLocation
可以實現的功能:定位是一個很常用的功能,如一些地圖軟件打開之後如果用戶允許軟件定位的話,那麼打開軟件後就會自動鎖定到當前位置,如果用戶手機移動那麼當前位置也會跟隨著變化。要實現這個功能需要使用CoreLoaction
中CLLocationManager
類,下面是這個類的使用說明:
+ (BOOL)locationServicesEnabled;/* 返回用戶是否啟用定位服務 */
+ (CLAuthorizationStatus)authorizationStatus;/* 定位服務授權狀態,返回枚舉類型 */
typedefNS_ENUM(int,CLAuthorizationStatus){
kCLAuthorizationStatusNotDetermined = 0, /* 用戶尚未決定是否啟用定位服務 */
kCLAuthorizationStatusRestricted, /* 沒有獲得用戶授權 */
kCLAuthorizationStatusDenied, /* 用戶禁止使用定位或者定位服務處於關閉狀態 */
kCLAuthorizationStatusAuthorizedAlways, /*前台、後台定位授權 */
kCLAuthorizationStatusAuthorizedWhenInUse, /* 前台定位授權 */
};
desiredAccuracy
: distanceFilter
: kCLDistanceFilterNone
,表示不進行距離限制
#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;/* 請求獲得應用前後台定位授權 */
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;
#import
- (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:
方法對指定區域進行監控。
在前台的基礎上,勾選後台模式Location updates
NSLocationWhenInUseUsageDescription
為YES
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; //關聯的或利益相關的地標