介紹
1.導(dǎo)入主頭文件 #import <CoreLocation/CoreLocation.h>
2.地圖和定位功能基于2個框架進行開發(fā):
(1)Map Kit :用于地圖展示
(2)CoreLocation:用于地理定位,有時只用定位,比如外賣,只有需要顯示地圖才用map kit
3.2個熱門專業(yè)術(shù)語:
(1)LBS :Location Based Service 位置服務(wù),又稱定位服務(wù)
LBS的服務(wù)歸納為四類:定位(個人位置定位)、導(dǎo)航(路徑導(dǎo)航)、查詢(查詢某個人或某個對象)、識別(識別某個人或?qū)ο?、事件檢查(當出現(xiàn)特殊情況下向相關(guān)機構(gòu)發(fā)送帶求救或查詢的個人位置信息)。
(2)SoLoMo :Social Local Mobile(索羅門) 移動社交
4.天朝的經(jīng)緯度范圍:緯度范圍:N 3°51′ ~ N 53°33′ 經(jīng)度范圍:E 73°33′ ~ E 135°05′
1、如果定位方法不走原因:
(1)沒有配置 plist 鍵值
(2)模擬器 bug
(3)沒有使用 strong 的屬性
2、邏輯結(jié)構(gòu)

請求用戶授權(quán)方法
注意:
- 一步代碼,一步plist配置
- 請求授權(quán)iOS8以后才有,一定注意版本適配!
- 如果同時實現(xiàn)兩個請求, 第一次運行會彈出第一個, 第二次運行會彈出第二個,大部分應(yīng)用程序只需要使用用戶使用期間授權(quán)即可
-
如果程序列表中出現(xiàn)了3行(即永不定位,使用應(yīng)用期間,始終定位),說明實現(xiàn)了2種授權(quán)
設(shè)置界面 - plist添加的用戶提示信息可以不寫值,表示空白提示,一般寫上需要定位的原因,提高用戶打開的幾率
1. 代碼:
if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
// 永久授權(quán)
[self.locationManager requestAlwaysAuthorization];
//用戶使用時授權(quán),大部分的應(yīng)用應(yīng)該使用此種授權(quán)方式,當能看見程序時才能定位
[self.locationManager requestWhenInUseAuthorization];
}
}
2. plist文件配置
① 使用期間授權(quán):添加該鍵,值是用戶提示信息
NSLocationWhenInUseUsageDescription

② 永久始終授權(quán):添加該鍵,值是用戶提示信息
NSLocationAlwaysUsageDescription

③ iOS9.0新特性:臨時獲取后臺定位權(quán)限(永久授權(quán))
注意:該方式進入后臺后會有提示

代碼:iOS9 臨時開啟后臺定位, allowsBackgroundLocationUpdates屬性設(shè)置為YES
if ([UIDevice currentDevice].systemVersion.floatValue >= 9.0) {
self.locationManager.allowsBackgroundLocationUpdates = YES;
}
plist:需要配置Plist,不然會崩潰,是一個數(shù)組,值添加到一個數(shù)組的對象當中
鍵 :Required background modes 數(shù)組值:App registers for location updates

CLLocationManager 屬性和方法
注意:
- 想要使用定位, 必須使用CLLocationManager(位置管理器)創(chuàng)建一個對象
- iOS8以后, 要定位, 必須使用位置管理器授權(quán),并配置plist
-
使用期間授權(quán):APP退到后臺就不進行定位了
始終授權(quán):后臺也會進行定位,例如記錄跑步,持續(xù)定位需要對電量做些優(yōu)化(設(shè)置兩個屬性)
設(shè)置界面 - 一般請求定位放在appDelegate中,在加載頁面之前就定位好
下面兩個屬性設(shè)置后可以降低代理方法調(diào)用頻率(默認大約一秒調(diào)用一次),以此省電,始終持續(xù)定位時候建議使用
屬性:
- 距離篩選器,每隔多少米定位一次,單位:米,當用戶發(fā)生一定位置的改變時, 再去調(diào)用代理方法, 以此實現(xiàn)省電
@property(assign, nonatomic) CLLocationDistance distanceFilter;
例子:每隔十米定位一次
self.locationManager.distanceFilter = 10;
- 定位精確度(越精確就越耗電)
@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;
降低精準度,實際上降低了與衛(wèi)星之間的計算,以此節(jié)省電量
Iphone的定位方式:(1)GPS(2)wifi定位(3)移動基站定位(流量)
例子:設(shè)置定位精度誤差一千米
self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
枚舉值:iOS9以前默認kCLLocationAccuracyBest
kCLLocationAccuracyBestForNavigation 最精確的定位
kCLLocationAccuracyBest; 最好的
kCLLocationAccuracyNearestTenMeters; 十米誤差
kCLLocationAccuracyHundredMeters; 一百米
kCLLocationAccuracyKilometer; 一千米
kCLLocationAccuracyThreeKilometers; 三千米
方法:
1.開始用戶定位
- (void) startUpdatingLocation;
2.停止用戶定位
- (void) stopUpdatingLocation;
代理方法
當調(diào)用了startUpdatingLocation方法后,就開始不斷地調(diào)用該代理方法定位用戶的位置,locations參數(shù)里面裝著一組CLLocation對象,持續(xù)定位需要設(shè)置 distanceFilter 和 desiredAccuracy 屬性
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
CLLocation 位置對象介紹
CLLocation用來表示某個位置的地理信息,比如經(jīng)緯度、海拔等等,創(chuàng)建一個 CLLocation對象只需要兩個參數(shù):緯度和經(jīng)度
屬性:
(1)2D位置坐標,經(jīng)緯度
@property(readonly, nonatomic) CLLocationCoordinate2D coordinate;
CLLocationDegrees latitude 緯度
CLLocationDegrees longitude 經(jīng)度
(2)海拔
@property(readonly, nonatomic) CLLocationDistance altitude;
(3)速度(單位是m/s)
@property(readonly, nonatomic) CLLocationSpeed speed;
(4)水平 垂直精準度
@property(readonly, nonatomic) CLLocationAccuracy horizontalAccuracy;
@property(readonly, nonatomic) CLLocationAccuracy verticalAccuracy;
(5)航向(取值范圍是0.0° ~ 359.9°,0.0°代表真北方向)
@property(readonly, nonatomic) CLLocationDirection course;
(6)時間戳,什么時間進行的定位
@property(readonly, nonatomic, copy) NSDate *timestamp;
方法:
(1)創(chuàng)建一個 CLLocation對象只需要兩個參數(shù):緯度和經(jīng)度
- (instancetype)initWithLatitude:(CLLocationDegrees)latitude
longitude:(CLLocationDegrees)longitude;
(2)計算2個位置之間的距離,比較的是直線距離,單位是米,除以1000可以換算成千米
- (CLLocationDistance)distanceFromLocation:(constCLLocation *)location;
例子:計算北京和西安的位置直線距離
CLLocation *location1 = [[CLLocation alloc] initWithLatitude:40.06 longitude:116.39];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:34.27 longitude:108.93];
CGFloat distance = [location2 distanceFromLocation:location1];
NSLog(@"distance: %f",distance / 1000);
例子:定位功能實現(xiàn)
1、 創(chuàng)建位置管理器
self.locationManager = [CLLocationManager new];
2、 請求用戶授權(quán)(iOS8以后才有) 同時配置 plist 列表,注意:必須使用版本判斷,建議結(jié)合使用
-----------------------------
有兩種授權(quán)方式,還有一種始終 requestAlwaysAuthorization
if([self.locationManagerrespondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
3、 設(shè)置 <CLLocationManagerDelegate>代理, 來獲取用戶位置數(shù)據(jù)
self.locationManager.delegate = self;
4、調(diào)用開始定位方法
[self.locationManager startUpdatingLocation];
5、實現(xiàn)代理方法拿到數(shù)據(jù),當用戶更新位置的時候調(diào)用此方法,頻繁調(diào)用, 非常耗電
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
//CLLocation 位置對象 --> 經(jīng)緯度
//CLLocationCoordinate2D coordinate 經(jīng)緯度
//獲取最后一次位置信息
CLLocation *location = locations.lastObject;
//輸出緯度和經(jīng)度
NSLog(@"latitude: %f,longitude: %f",location.coordinate.latitude, location.coordinate.longitude);
// 停止定位
[self.locationManager stopUpdatingLocation];
}
三、地理編碼的實現(xiàn)
- 正地理編碼:將地名轉(zhuǎn)換成經(jīng)緯度的過程
步驟:
(1)創(chuàng)建一個GLGeocoder對象
(2)實現(xiàn)地理編碼方法
(3)遍歷數(shù)組,獲取數(shù)據(jù)(可能返回多個相同地名),如果對象大于1,應(yīng)該給用戶一個列表選擇
- 反地理編碼:將經(jīng)緯度轉(zhuǎn)換成地名的過程
步驟:
(1)創(chuàng)建一個GLGeocoder對象
(2)創(chuàng)建一個CLLoction對象(經(jīng)緯度)
(3)實現(xiàn)反地理編碼方法
(4)遍歷數(shù)組,獲取數(shù)組
CLGeocoder地理編碼對象
一個屬性:
@property (nonatomic, readonly, getter=isGeocoding) BOOL geocoding;
方法:
1、三個正地理編碼方法
(1)
- (void)geocodeAddressDictionary:(NSDictionary *)addressDictionary completionHandler:(CLGeocodeCompletionHandler)completionHandler;
(2)最簡單的,填入要搜索的位置,回調(diào)出搜索信息
- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
(3)
- (void)geocodeAddressString:(NSString *)addressString inRegion:(nullable CLRegion *)region completionHandler:(CLGeocodeCompletionHandler)completionHandler;
2、一個反地理編碼方法
- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
3、取消編碼
- (void)cancelGeocode;
回調(diào)的block參數(shù)CLGeocodeCompletionHandler
typedef void (^CLGeocodeCompletionHandler)(NSArray< CLPlacemark *> * __nullable placemarks, NSError * __nullable error);
block參數(shù):
- placemarks:CLPlacemark 地標對象,里面封裝各種詳細地址信息,如街道名,城市名,國家名等
- error :當編碼出錯時有值(比如編碼不出具體的信息)
CLPlacemark 地標對象:
- (instancetype)initWithPlacemark:(CLPlacemark *) placemark;
1、主要獲取的屬性,位置對象,能獲取到經(jīng)緯度信息
@property (nonatomic, readonly, copy, nullable) CLLocation *location;
@property (nonatomic, readonly, copy, nullable) CLRegion *region;
@property (nonatomic, readonly, copy, nullable) NSTimeZone *timeZone ( 9_0))
@property (nonatomic, readonly, copy, nullable) NSDictionary *addressDictionary;
詳細地址名(包括等到門牌等)
@property (nonatomic, readonly, copy, nullable) NSString *name;
街道名
@property (nonatomic, readonly, copy, nullable) NSString *thoroughfare;
子街道名
@property (nonatomic, readonly, copy, nullable) NSString *subThoroughfare;
城市
@property (nonatomic, readonly, copy, nullable) NSString *locality;
子城市
@property (nonatomic, readonly, copy, nullable) NSString *subLocality;
行政區(qū)域
@property (nonatomic, readonly, copy, nullable) NSString *administrativeArea;
子行政區(qū)域
@property (nonatomic, readonly, copy, nullable) NSString *subAdministrativeArea;
@property (nonatomic, readonly, copy, nullable) NSString *postalCode;
@property (nonatomic, readonly, copy, nullable) NSString *ISOcountryCode;
國家
@property (nonatomic, readonly, copy, nullable) NSString *country;
@property (nonatomic, readonly, copy, nullable) NSString *inlandWater;
@property (nonatomic, readonly, copy, nullable) NSString *ocean;
@property (nonatomic, readonly, copy, nullable) NSArray<NSString *> *areasOfInterest;
正地理編碼例子
//1. 創(chuàng)建 Geocoder
CLGeocoder *geocoder = [CLGeocoder new];
//2. 調(diào)用方法
[geocoder geocodeAddressString:self.addressTF.text completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
//3.1 防錯處理
if (placemarks.count == 0 || error) {
NSLog(@"沒有數(shù)據(jù)或數(shù)據(jù)解析出錯");
return;
}
//3.2 遍歷地標數(shù)組placemarks,地理編碼容易出現(xiàn)多個地標,應(yīng)該給用戶一個列表去選擇
for (CLPlacemark *pm in placemarks) {
//3.3 設(shè)置緯度
self.latitudeLabel.text = [NSString stringWithFormat:@"%f",pm.location.coordinate.latitude];
//3.4 設(shè)置經(jīng)度
self.longitudeLabel.text = [NSString stringWithFormat:@"%f",pm.location.coordinate.longitude];
//3.5 設(shè)置地址
self.detailAddressLabel.text = pm.name;
}
}];
反地理編碼例子
//1. 創(chuàng)建 Geocoder 對象
CLGeocoder *geocoder = [CLGeocoder new];
//2. 創(chuàng)建 CLLocation對象,輸入經(jīng)緯度信息
CLLocation *location = [[CLLocation alloc] initWithLatitude:[self.latitudeTF.text floatValue] longitude:[self.longitudeTF.text floatValue]];
//3. 調(diào)用反地理編碼方法
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
//3.1 防錯處理
if (placemarks.count == 0 || error) {
NSLog(@"沒有數(shù)據(jù)或數(shù)據(jù)解析出錯");
return;
}
//3.2 遍歷數(shù)據(jù)
for (CLPlacemark *pm in placemarks) {
//3.3. 獲取城市信息, 如果有城市信息就顯示, 否則可以顯示行政區(qū)域
if (pm.locality) {
//locality : 城市
self.cityLabel.text = pm.locality;
} else {
//administrativeArea : 行政區(qū)域
self.cityLabel.text = pm.administrativeArea;
}
}
}];

