CLLocation - 位置對(duì)象
CLLocation對(duì)象包含設(shè)備的地理位置和高度,以及指示這些測(cè)量精度和收集時(shí)間的值历涝。在iOS操作系統(tǒng)中,位置對(duì)象還包含航向信息,即設(shè)備移動(dòng)的速度和航向烛缔。
通常不需要自己創(chuàng)建CLLocation對(duì)象馏段。從CLLocationManager對(duì)象請(qǐng)求位置更新后,系統(tǒng)使用板載傳感器收集位置數(shù)據(jù)践瓷,并將數(shù)據(jù)報(bào)告給應(yīng)用程序院喜。一些服務(wù)還會(huì)返回之前收集的位置數(shù)據(jù),可以將這些數(shù)據(jù)作為上下文來改進(jìn)服務(wù)晕翠。始終可以從CLLocationManager對(duì)象的UIApplicationLaunchOptionsLocationKey屬性中檢索最近收集的位置喷舀。如果要緩存自定義位置數(shù)據(jù)或計(jì)算兩個(gè)地理坐標(biāo)之間的距離,可以自己創(chuàng)建location對(duì)象淋肾。需要按原樣使用CLLocation對(duì)象硫麻,不要子類化它們。
常用類型定義
typedef double CLLocationDegrees;
類型定義 :用于表示W(wǎng)GS 84參考坐標(biāo)系下緯度或經(jīng)度坐標(biāo)(以度為單位)的類型樊卓。單位度數(shù)可以是正(北和東)或負(fù)(南和西)拿愧。
例如 :
CLLocationDegrees latitude = 45.148327;
CLLocationDegrees longitude = 124.818265;
typedef double CLLocationAccuracy;
類型定義 :用于表示以米為單位的位置精度級(jí)別的類型。單位為米的值越低碌尔,位置的物理精度就越高浇辜。負(fù)精度值表示位置無效。
typedef double CLLocationSpeed;
類型定義 :設(shè)備移動(dòng)的速度(以米每秒為單位的類型)唾戚。
typedef double CLLocationDirection;
類型定義 :相對(duì)于正北以度數(shù)測(cè)量的方位角奢赂。方向值從正北開始以度為單位測(cè)量,并圍繞指南針順時(shí)針繼續(xù)颈走。因此膳灶,北是0度,東是90度立由,南是180度轧钓,以此類推。負(fù)值表示方向無效锐膜。
struct CLLocationCoordinate2D {
CLLocationDegrees latitude;
CLLocationDegrees longitude;
};
typedef struct CLLocationCoordinate2D CLLocationCoordinate2D;
結(jié)構(gòu)體描述 :使用WGS 84參考坐標(biāo)系指定的與位置相關(guān)聯(lián)的緯度和經(jīng)度毕箍。
CL_EXTERN
CLLocationCoordinate2D CLLocationCoordinate2DMake(CLLocationDegrees latitude, CLLocationDegrees longitude) API_AVAILABLE(ios(4.0), macos(10.7));
函數(shù)描述 :將緯度和經(jīng)度值格式化為坐標(biāo)數(shù)據(jù)結(jié)構(gòu)格式。
參數(shù) :
latitude : 新坐標(biāo)的緯度道盏。
longitude : 新坐標(biāo)的經(jīng)度而柑。
返回值 : 包含緯度和經(jīng)度值的坐標(biāo)結(jié)構(gòu)。
例如:
CLLocationDegrees latitude = 45.148327;
CLLocationDegrees longitude = 124.818265;
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);
CLLocationManager - 位置管理器
CLLocationManager荷逞,用于啟動(dòng)和停止向應(yīng)用程序傳遞位置相關(guān)事件的對(duì)象≈衷叮可以使用該類的實(shí)例來配置涩澡、啟動(dòng)和停止Core Location(核心位置)服務(wù)。位置管理器對(duì)象支持以下與位置相關(guān)的活動(dòng):
- 以可配置的精確度跟蹤用戶當(dāng)前位置的大小變化坠敷。
- 報(bào)告來自船上羅盤的航向變化妙同。(iOS)
- 監(jiān)視感興趣的不同區(qū)域射富,并在用戶進(jìn)入或離開這些區(qū)域時(shí)生成位置事件。
- 當(dāng)應(yīng)用程序在后臺(tái)時(shí)粥帚,延遲位置更新的交付胰耗。(iOS)
- 向附近的信標(biāo)報(bào)告范圍。
準(zhǔn)備使用定位服務(wù)時(shí)芒涡,請(qǐng)執(zhí)行以下步驟:
- 1.查看應(yīng)用程序是否被授權(quán)使用位置服務(wù)柴灯,如果您的應(yīng)用程序的授權(quán)狀態(tài)尚未確定,則請(qǐng)求權(quán)限拖陆。
- 2.檢查是否有適當(dāng)?shù)奈恢梅?wù)可供使用弛槐。
- 3.創(chuàng)建一個(gè)CLLocationManager類的實(shí)例懊亡,并在應(yīng)用程序的某個(gè)地方存儲(chǔ)對(duì)它的強(qiáng)引用依啰。在所有涉及到該對(duì)象的任務(wù)完成之前,需要保持對(duì)CLLocationManager對(duì)象的強(qiáng)引用店枣。由于大多數(shù)位置管理器任務(wù)是異步運(yùn)行的速警,因此將位置管理器存儲(chǔ)在局部變量中是不夠的。
- 4.將自定義對(duì)象指定給代理屬性鸯两。此對(duì)象必須符合CLLocationManagerDelegate協(xié)議闷旧。
- 5.配置與要使用的服務(wù)相關(guān)的屬性。例如钧唐,在獲取位置更新時(shí)忙灼,始終配置distanceFilter和desiredAccuracy屬性。
- 6.調(diào)用適當(dāng)?shù)姆椒▉韱?dòng)事件的交付钝侠。
對(duì)于使用的服務(wù)该园,請(qǐng)準(zhǔn)確配置與該服務(wù)關(guān)聯(lián)的任何屬性。Core Location(核心位置)通過在不需要時(shí)關(guān)閉硬件來積極地管理電源帅韧。例如里初,將位置事件所需的精度設(shè)置為1公里,可使位置管理器靈活地關(guān)閉GPS硬件忽舟,并僅依賴WiFi或蜂窩無線電双妨,這可顯著節(jié)省電力。
所有與位置和標(biāo)題相關(guān)的更新都將傳遞到關(guān)聯(lián)的代理對(duì)象叮阅,該對(duì)象是您提供的自定義對(duì)象刁品。
CLLocationManager常用屬性
@property(assign, nonatomic) CLLocationDegrees headingFilter API_AVAILABLE(ios(3.0)) API_UNAVAILABLE(watchos, tvos, macOS);
屬性描述 :生成新航向事件所需的最小角度變化(以度為單位)。角度距離是相對(duì)于上次交付的航向事件測(cè)量的浩姥。使用值kCLHeadingFilterNone通知所有移動(dòng)哑诊。此屬性的默認(rèn)值為1度。
@property(assign, nonatomic) CLLocationDistance distanceFilter;
屬性描述 :在生成更新事件之前及刻,設(shè)備必須水平移動(dòng)的最小距離(以米為單位)镀裤。此距離是相對(duì)于先前交付的位置測(cè)量的竞阐。使用值kCLDistanceFilterNone通知所有移動(dòng)。此屬性的默認(rèn)值為kCLDistanceFilterNone暑劝。此屬性僅與標(biāo)準(zhǔn)位置服務(wù)一起使用骆莹,在監(jiān)視重要位置更改時(shí)不使用。
@property (readonly, nonatomic) CLLocationDistance maximumRegionMonitoringDistance API_AVAILABLE(ios(4.0), macos(10.8)) API_UNAVAILABLE(watchos, tvOS);
屬性描述 :可以指定給區(qū)域的最大邊界距離担猛。此屬性定義從區(qū)域中心點(diǎn)允許的最大邊界距離幕垦。嘗試監(jiān)視距離大于此值的區(qū)域?qū)?dǎo)致位置管理器向委托發(fā)送kclerRorrorRegionMonitoringFailure錯(cuò)誤。如果區(qū)域監(jiān)視不可用或不受支持傅联,則此屬性中的值為-1先改。
@property (readonly, nonatomic, copy) NSSet<__kindof CLRegion *> *monitoredRegions API_AVAILABLE(ios(4.0), macos(10.8)) API_UNAVAILABLE(watchos, tvOS);
屬性描述 :由所有位置管理器對(duì)象(CLLocationManager對(duì)象)監(jiān)視的共享區(qū)域集。不能直接將區(qū)域添加到此屬性蒸走。相反仇奶,必須通過調(diào)用startMonitoringForRegion:方法來注冊(cè)區(qū)域。此屬性中的區(qū)域由應(yīng)用程序中CLLocationManager類的所有實(shí)例共享比驻。
此集合中的對(duì)象不一定與注冊(cè)時(shí)指定的對(duì)象相同该溯。系統(tǒng)只維護(hù)區(qū)域數(shù)據(jù)本身。因此别惦,唯一標(biāo)識(shí)已注冊(cè)區(qū)域的方法是使用其標(biāo)識(shí)符屬性狈茉。
位置管理器在應(yīng)用程序啟動(dòng)之間保存區(qū)域數(shù)據(jù)。如果應(yīng)用程序被終止然后重新啟動(dòng)掸掸,則此屬性的內(nèi)容將重新填充包含先前注冊(cè)數(shù)據(jù)的區(qū)域?qū)ο蟆?/p>
CLLocationManager常用函數(shù)
+ (BOOL)locationServicesEnabled API_AVAILABLE(ios(4.0), macos(10.7));
函數(shù)描述 :返回一個(gè)布爾值氯庆,指示整個(gè)設(shè)備上是否啟用了位置服務(wù)。在開始位置更新之前扰付,可以檢查此方法的返回值堤撵,以確定設(shè)備是否啟用了位置服務(wù)。如果在禁用位置服務(wù)時(shí)嘗試啟動(dòng)位置更新悯周,則位置管理器將向其代理報(bào)告錯(cuò)誤粒督。用戶通常可以通過切換位置服務(wù)開關(guān)從設(shè)置應(yīng)用程序啟用或禁用位置服務(wù)禽翼。
返回值 : 如果已啟用位置服務(wù)屠橄,則為“YES”;如果未啟用位置服務(wù)闰挡,則為“NO”锐墙。
反應(yīng)了這里的設(shè)置:
+ (CLAuthorizationStatus)authorizationStatus API_AVAILABLE(ios(4.2), macos(10.7));
函數(shù)描述 :返回應(yīng)用程序使用位置服務(wù)的授權(quán)狀態(tài)。給定應(yīng)用程序的授權(quán)狀態(tài)由系統(tǒng)管理长酗,并由多個(gè)因素決定溪北。應(yīng)用程序必須由用戶明確授權(quán)使用定位服務(wù),并且定位服務(wù)本身當(dāng)前必須為系統(tǒng)啟用。當(dāng)應(yīng)用程序首次嘗試使用定位服務(wù)時(shí)之拨,將自動(dòng)顯示用戶授權(quán)請(qǐng)求茉继。
返回值 : 指示應(yīng)用程序是否被授權(quán)使用位置服務(wù)的值。
CLAuthorizationStatus提供的枚舉值:
typedef NS_ENUM(int, CLAuthorizationStatus) {
//用戶尚未選擇應(yīng)用程序是否可以使用位置服務(wù)蚀乔。
//當(dāng)未確定授權(quán)狀態(tài)時(shí)如果應(yīng)用程序位于前臺(tái)烁竭,請(qǐng)求授權(quán)將導(dǎo)致位置管理器提示用戶獲得權(quán)限。
kCLAuthorizationStatusNotDetermined = 0,
//由于某些原因(如家長控制)對(duì)位置服務(wù)的有效限制吉挣,此應(yīng)用程序無權(quán)使用位置服務(wù)派撕。
//用戶無法更改此狀態(tài)
kCLAuthorizationStatusRestricted,
//拒絕對(duì)此應(yīng)用程序的位置授權(quán)
//用戶已明確拒絕對(duì)此應(yīng)用程序的位置授權(quán),或者在設(shè)置中全局禁用了位置服務(wù)睬魂,或者位置服務(wù)不可用(如飛行模式)疲扎。
kCLAuthorizationStatusDenied,
//用戶授權(quán)應(yīng)用程序隨時(shí)啟動(dòng)定位服務(wù)的權(quán)限杠氢。
//該授權(quán)允許使用所有位置服務(wù)希痴,并接收位置事件躏敢,無應(yīng)用程序是否正在使用。
//應(yīng)用程序可能會(huì)通過諸如訪問監(jiān)控蛙粘、區(qū)域監(jiān)控和重大位置變化監(jiān)控等監(jiān)控api被在后臺(tái)啟動(dòng)垫卤。
kCLAuthorizationStatusAuthorizedAlways API_AVAILABLE(macos(10.12), ios(8.0)),
//用戶已授權(quán)僅在使用應(yīng)用程序時(shí)有訪問位置的權(quán)限
//此授權(quán)允許僅在應(yīng)用程序正在使用時(shí)使用所有位置服務(wù)和接收位置事件威彰。
//若要繼續(xù)在后臺(tái)使用位置服務(wù)出牧,需要啟用連續(xù)后臺(tái)位置更新
//通過allowsBackgroundLocationUpdates可以啟用連續(xù)后臺(tái)位置更新
kCLAuthorizationStatusAuthorizedWhenInUse API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macOS),
//MacOS使用,iOS歇盼、tvOS和watchOS上不推薦或禁止使用此值舔痕。用戶已授權(quán)此應(yīng)用程序使用位置服務(wù)。
kCLAuthorizationStatusAuthorized API_DEPRECATED("Use kCLAuthorizationStatusAuthorizedAlways", ios(2.0, 8.0)) API_AVAILABLE(macos(10.6)) API_UNAVAILABLE(watchos, tvos) = kCLAuthorizationStatusAuthorizedAlways
};
反應(yīng)了這里的設(shè)置:
- (void)requestWhenInUseAuthorization API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macOS);
函數(shù)描述 :請(qǐng)求在應(yīng)用程序位于前臺(tái)時(shí)使用定位服務(wù)的權(quán)限豹缀。當(dāng)前授權(quán)狀態(tài)為kCLAuthorizationStatusNotDetermined時(shí)伯复,此方法將異步運(yùn)行,并提示用戶授予應(yīng)用程序使用位置服務(wù)的權(quán)限邢笙。用戶提示包含應(yīng)用程序Info.plist文件中NSLocationWhenInUseUsageDescription密鑰的文本啸如,調(diào)用此方法時(shí)需要該密鑰的存在。確定狀態(tài)后氮惯,位置管理器將結(jié)果傳遞給代理的locationManager:didChangeAuthorizationStatus:方法叮雳。如果當(dāng)前授權(quán)狀態(tài)不是kCLAuthorizationStatusNotDetermined,則此方法不執(zhí)行任何操作妇汗,也不調(diào)用locationManager:didChangeAuthorizationStatus:方法帘不。
在使用定位服務(wù)之前,必須調(diào)用此方法或requestAlwaysAuthorization方法杨箭。如果用戶授予應(yīng)用“使用時(shí)”授權(quán)寞焙,你的應(yīng)用可以在前臺(tái)啟動(dòng)大部分(但不是全部)位置服務(wù)(應(yīng)用程序無法自動(dòng)啟動(dòng)例如區(qū)域監(jiān)視或重要位置更改服務(wù)的應(yīng)用程序的服務(wù))。在前臺(tái)啟動(dòng)時(shí),如果應(yīng)用程序已在Xcode項(xiàng)目的“ Capabilities”選項(xiàng)卡中啟用后臺(tái)位置更新捣郊,則服務(wù)將繼續(xù)在后臺(tái)運(yùn)行辽狈。在后臺(tái)運(yùn)行應(yīng)用程序時(shí)嘗試啟動(dòng)定位服務(wù)將失敗。當(dāng)應(yīng)用程序移動(dòng)到具有活動(dòng)位置服務(wù)的后臺(tái)時(shí)呛牲,系統(tǒng)會(huì)在狀態(tài)欄中顯示位置服務(wù)指示器稻艰。
注 :如不設(shè)置 Info.plist文件,控制器會(huì)打印提醒:
This app has attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain both “NSLocationAlwaysAndWhenInUseUsageDescription” and “NSLocationWhenInUseUsageDescription” keys with string values explaining to the user how the app uses this data(此應(yīng)用試圖訪問隱私敏感數(shù)據(jù)侈净,但沒有使用說明尊勿。應(yīng)用程序的Info.plist必須同時(shí)包含“ NSLocationAlwaysAndWhenInUseUsageDescription”和“ NSLocationWhenInUseUsageDescription”鍵,這些鍵的字符串值向用戶解釋應(yīng)用程序如何使用此數(shù)據(jù))
- (void)startUpdatingLocation API_AVAILABLE(watchos(3.0)) API_UNAVAILABLE(tvOS);
函數(shù)描述 :開始生成報(bào)告用戶當(dāng)前位置的更新畜侦。此方法立即返回元扔。調(diào)用此方法將導(dǎo)致位置管理器獲得初始位置修復(fù)(可能需要幾秒鐘),并通過調(diào)用其locationManager:didUpdateLocations:方法來通知代理旋膳。之后澎语,調(diào)用方主要在超過distanceFilter屬性中的值時(shí)生成更新事件。不過验懊,在其他情況下也可能會(huì)提供更新擅羞,例如硬件收集到更準(zhǔn)確的位置讀數(shù),則調(diào)用方可以發(fā)送另一個(gè)通知义图。
連續(xù)多次調(diào)用此方法不會(huì)自動(dòng)生成新事件减俏。但在中間調(diào)用stopUpdateLocation會(huì)導(dǎo)致下次調(diào)用此方法時(shí)發(fā)送新的初始事件。
如果啟動(dòng)此服務(wù)并且應(yīng)用程序掛起碱工,則系統(tǒng)將停止傳遞事件娃承,直到應(yīng)用程序重新開始運(yùn)行(在前臺(tái)或后臺(tái))。如果應(yīng)用程序已終止怕篷,則新位置事件的傳遞將完全停止历筝。因此,如果應(yīng)用需要在后臺(tái)接收位置事件廊谓,它必須在Info.plist文件中包含UIBackgroundModes鍵(帶有位置值)梳猪。
除了實(shí)現(xiàn)locationManager:didUpdateLocations:方法的委托對(duì)象外,還應(yīng)該實(shí)現(xiàn)locationManager:didFailWithError:方法以響應(yīng)潛在的錯(cuò)誤蒸痹。
- (void)stopUpdatingLocation;
函數(shù)描述 :停止生成位置更新春弥。只要代碼不再需要接收與位置相關(guān)的事件,就調(diào)用此方法电抚。禁用事件傳遞使接收器可以在沒有客戶端需要位置數(shù)據(jù)時(shí)禁用適當(dāng)?shù)挠布?從而節(jié)省電源)惕稻。始終可以通過再次調(diào)用startUpdatingLocation方法重新啟動(dòng)位置更新的生成。
+ (BOOL)headingAvailable API_AVAILABLE(ios(4.0), macos(10.7)) API_UNAVAILABLE(watchos, tvOS);
函數(shù)描述 :返回一個(gè)布爾值蝙叛,指示位置管理器是否能夠生成與導(dǎo)航方向相關(guān)的事件俺祠。在要求位置管理器傳遞與導(dǎo)航方向相關(guān)的事件之前,應(yīng)檢查此方法返回的值。
返回值 : 如果航向數(shù)據(jù)可用蜘渣,則為“YES”淌铐;如果不可用,則為“NO”蔫缸。
- (void)startUpdatingHeading API_AVAILABLE(ios(3.0)) API_UNAVAILABLE(watchos, tvos, macOS);
函數(shù)描述 :開始生成報(bào)告用戶當(dāng)前導(dǎo)航方向的更新腿准。此方法立即返回。當(dāng)調(diào)用方已經(jīng)停止導(dǎo)航方向的更新時(shí)拾碌,調(diào)用此方法將導(dǎo)致它獲取初始航向并通知代理吐葱。此外,當(dāng)超過headingFilter屬性中的值時(shí)校翔,調(diào)用方生成更新事件弟跑。
在調(diào)用此方法之前,應(yīng)始終檢查headingAvailable屬性防症,以查看當(dāng)前設(shè)備上是否支持導(dǎo)航方向信息孟辑。如果不支持導(dǎo)航方向信息,則調(diào)用此方法無效蔫敲,并且不會(huì)將事件傳遞給代理饲嗽。
連續(xù)多次調(diào)用此方法不會(huì)自動(dòng)生成新事件。但在中間調(diào)用stopUpdatengHeading會(huì)導(dǎo)致下次調(diào)用此方法時(shí)發(fā)送新的初始事件奈嘿。
如果啟動(dòng)此服務(wù)并且應(yīng)用程序掛起貌虾,則系統(tǒng)將停止傳遞事件,直到應(yīng)用程序重新開始運(yùn)行(在前臺(tái)或后臺(tái))指么。如果應(yīng)用程序已終止酝惧,則新航向事件的傳遞將完全停止榴鼎,并且必須在應(yīng)用程序重新啟動(dòng)時(shí)由代碼重新啟動(dòng)伯诬。
航向事件將傳遞到委托的locationManager:didUpdateHeading:方法。如果出現(xiàn)錯(cuò)誤巫财,位置管理器將改為調(diào)用委托的locationManager:didFailWithError:方法盗似。
- (void)stopUpdatingHeading API_AVAILABLE(ios(3.0)) API_UNAVAILABLE(watchos, tvos, macOS);
函數(shù)描述 : 停止生成航向更新。只要代碼不再需要接收與航向相關(guān)的事件平项,就調(diào)用此方法赫舒。禁用事件傳遞使接收器可以在沒有客戶端需要位置數(shù)據(jù)時(shí)禁用適當(dāng)?shù)挠布?從而節(jié)省電源)。始終可以通過再次調(diào)用startUpdatingHeading方法來重新啟動(dòng)航向更新的生成闽瓢。
+ (BOOL)isMonitoringAvailableForClass:(Class)regionClass API_AVAILABLE(ios(7.0), macos(10.10)) API_UNAVAILABLE(watchos, tvOS);
函數(shù)描述 :返回一個(gè)布爾值接癌,指示設(shè)備是否支持使用指定類進(jìn)行區(qū)域監(jiān)聽。區(qū)域監(jiān)視支持的可用性取決于設(shè)備上存在的硬件扣讼。此方法不考慮位置服務(wù)的可用性或用戶可能已為應(yīng)用程序或系統(tǒng)禁用這些服務(wù)的事實(shí)缺猛,必須單獨(dú)確定應(yīng)用程序的授權(quán)狀態(tài)。
參數(shù) :
regionClass : MapKit框架中的區(qū)域監(jiān)視類。這個(gè)類必須從CLRegion類派生荔燎。
返回值 : 如果設(shè)備能夠使用指定的類監(jiān)視區(qū)域耻姥,則為“YES”;否則為“NO”有咨。
- (void)requestStateForRegion:(CLRegion *)region API_AVAILABLE(ios(7.0), macos(10.10)) API_UNAVAILABLE(watchos, tvOS);
函數(shù)描述 :異步檢索區(qū)域的狀態(tài)琐簇。 此方法異步執(zhí)行請(qǐng)求,并將結(jié)果傳遞給位置管理器的代理座享。必須在代理中實(shí)現(xiàn)locationManager:dideterminestate:forRegion:方法才能接收結(jié)果婉商。如果region參數(shù)包含未知類型的region對(duì)象,則此方法不執(zhí)行任何操作渣叛。
參數(shù) :
region : 想知道的地區(qū)据某。此對(duì)象必須是MapKit提供的標(biāo)準(zhǔn)區(qū)域子類之一的實(shí)例。不能使用此方法來確定自己定義的自定義區(qū)域的狀態(tài)诗箍。
- (void)startMonitoringForRegion:(CLRegion *)region API_AVAILABLE(ios(5.0), macos(10.8)) API_UNAVAILABLE(watchos, tvOS);
函數(shù)描述 :開始監(jiān)視指定區(qū)域癣籽。對(duì)于要監(jiān)視的每個(gè)區(qū)域,必須調(diào)用此方法一次滤祖。如果應(yīng)用程序已監(jiān)視具有相同標(biāo)識(shí)符的現(xiàn)有區(qū)域筷狼,則舊區(qū)域?qū)⑻鎿Q為新區(qū)域。使用此方法添加的區(qū)域由應(yīng)用程序中的所有CLLocationManager對(duì)象共享匠童,并存儲(chǔ)在monitoredRegions屬性中埂材。
區(qū)域事件將傳遞到代理的locationManager:didEnterRegion: 和locationManager:didExitRegion: 方法。如果出現(xiàn)錯(cuò)誤汤求,位置管理器將改為調(diào)用代理的locationManager:monitoringDidFailForRegion:withError: 方法俏险。一個(gè)應(yīng)用程序一次最多可以注冊(cè)20個(gè)區(qū)域。為了及時(shí)報(bào)告區(qū)域變化扬绪,區(qū)域監(jiān)視服務(wù)需要網(wǎng)絡(luò)連接竖独。
參數(shù) :
region : 定義要監(jiān)視的邊界的區(qū)域?qū)ο蟆4藚?shù)不能為nil挤牛。
- (void)stopMonitoringForRegion:(CLRegion *)region API_AVAILABLE(ios(4.0), macos(10.8)) API_UNAVAILABLE(watchos, tvOS);
函數(shù)描述 :停止監(jiān)視指定區(qū)域莹痢。如果指定的區(qū)域?qū)ο螽?dāng)前未被監(jiān)視,則此方法無效墓赴。
參數(shù) :
region : 當(dāng)前正在監(jiān)視的區(qū)域?qū)ο缶荷拧4藚?shù)不能為nil。
CLLocationManager代理函數(shù)
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray<CLLocation *> *)locations API_AVAILABLE(ios(6.0), macos(10.9));
函數(shù)描述 :通知代理新的位置數(shù)據(jù)可用诫硕。此方法的實(shí)現(xiàn)是可選的坦辟,但建議使用。
參數(shù) :
manager : 生成更新事件的位置管理器對(duì)象章办。
locations : 包含位置數(shù)據(jù)的CLLocation對(duì)象數(shù)組锉走。該數(shù)組始終包含至少一個(gè)表示當(dāng)前位置的對(duì)象滔吠。如果更新被延遲,或者多個(gè)位置在更新之前到達(dá)挠日,則數(shù)組可能包含其他條目疮绷。數(shù)組中的對(duì)象按照它們發(fā)生的順序組織。因此嚣潜,最近的位置更新位于數(shù)組的末尾冬骚。
- (void)locationManager:(CLLocationManager *)manager
didUpdateHeading:(CLHeading *)newHeading API_AVAILABLE(ios(3.0)) API_UNAVAILABLE(watchos, tvos, macOS);
函數(shù)描述 :通知代理位置管理器接收到更新的航向信息。此方法的實(shí)現(xiàn)是可選的懂算,但如果使用startUpdatingHeading方法開始標(biāo)題更新只冻,則此實(shí)現(xiàn)是預(yù)期的。locationManager對(duì)象在您最初啟動(dòng)航向服務(wù)之后調(diào)用這個(gè)方法计技。當(dāng)先前報(bào)告的值更改超過CLLocationManager對(duì)象的headingFilter屬性中指定的值時(shí)喜德,將傳遞后續(xù)事件。
參數(shù) :
manager : 生成更新事件的位置管理器對(duì)象垮媒。
newHeading : 新的航向數(shù)據(jù)舍悯。
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status API_AVAILABLE(ios(4.2), macos(10.7));
函數(shù)描述 :在應(yīng)用程序創(chuàng)建位置管理器時(shí)以及授權(quán)狀態(tài)更改時(shí)通知代理其授權(quán)狀態(tài)。當(dāng)應(yīng)用程序創(chuàng)建相關(guān)對(duì)象的CLLocationManager實(shí)例時(shí)睡雇,以及當(dāng)應(yīng)用程序的授權(quán)狀態(tài)更改時(shí)萌衬,系統(tǒng)調(diào)用此方法。狀態(tài)將通知應(yīng)用程序是否可以訪問用戶的位置它抱。
使用此代理方法來管理應(yīng)用程序的狀態(tài)更改秕豫,以響應(yīng)其使用位置信息的能力。例如根據(jù)需要啟用或禁用應(yīng)用程序的位置相關(guān)功能观蓄。
Core Location(核心位置)保證會(huì)調(diào)用locationManager:didChangeAuthorizationStatus:方法混移,當(dāng)用戶的操作導(dǎo)致授權(quán)狀態(tài)改變時(shí),以及當(dāng)你的應(yīng)用程序創(chuàng)建一個(gè)CLLocationManager實(shí)例時(shí)侮穿,無論你的應(yīng)用程序是在前臺(tái)還是后臺(tái)運(yùn)行歌径。
如果在調(diào)用requestWhenInUseAuthorization或requestAlwaysAuthorization方法之后,用戶的選擇沒有更改授權(quán)狀態(tài)撮珠,則位置管理器不會(huì)向該方法報(bào)告當(dāng)前的授權(quán)狀態(tài)沮脖,位置管理器只報(bào)告更改。例如芯急,當(dāng)狀態(tài)從kCLAuthorizationStatusNotDetermined更改為kCLAuthorizationStatusAuthorizedWhenInUse時(shí),位置管理器調(diào)用此方法驶俊。
參數(shù) :
manager : 報(bào)告事件的位置管理器對(duì)象娶耍。
status : 應(yīng)用程序的授權(quán)狀態(tài)。
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager API_AVAILABLE(ios(3.0)) API_UNAVAILABLE(watchos, tvos, macOS);
函數(shù)描述 :詢問代理是否應(yīng)顯示航向校準(zhǔn)警報(bào)饼酿。Core Location(核心位置)可調(diào)用此方法榕酒,以校準(zhǔn)用于確定航向值的機(jī)載硬件胚膊。通常,Core Location(核心位置)在以下時(shí)間調(diào)用此方法:
第一次請(qǐng)求航向更新想鹰,當(dāng)磁芯位置觀測(cè)到所觀測(cè)磁場的大小或傾角發(fā)生顯著變化時(shí)紊婉,如果您從該方法返回YES, Core Location(核心位置)將立即在當(dāng)前窗口的頂部顯示標(biāo)題校準(zhǔn)警告。校準(zhǔn)警報(bào)提示用戶以特定的模式移動(dòng)設(shè)備辑舷,以便核心位置能夠區(qū)分地球磁場和任何局部磁場喻犁。在完成校準(zhǔn)或通過調(diào)用dismissHeadingCalibrationDisplay方法顯式地取消警報(bào)之前,警報(bào)都是可見的何缓。在后一種情況下肢础,可以使用此方法設(shè)置計(jì)時(shí)器,并在指定時(shí)間量過后關(guān)閉接口碌廓。
校準(zhǔn)過程只能過濾掉隨設(shè)備移動(dòng)的磁場传轰。若要校準(zhǔn)靠近其他磁干擾源的設(shè)備,用戶必須將設(shè)備從磁干擾源處移開谷婆,或在校準(zhǔn)過程中將磁干擾源與設(shè)備一起移開慨蛙。
如果從此方法返回NO或在代理中沒有為其提供實(shí)現(xiàn),則核心位置不會(huì)顯示標(biāo)題校準(zhǔn)警告纪挎。即使沒有顯示警報(bào)股淡,當(dāng)任何干擾磁場遠(yuǎn)離設(shè)備時(shí),校準(zhǔn)仍然可以自然發(fā)生廷区。然而唯灵,如果設(shè)備由于任何原因無法校準(zhǔn)自身,任何后續(xù)事件的headingAccuracy屬性值將反映未校準(zhǔn)的讀數(shù)隙轻。
參數(shù) :
manager : 協(xié)調(diào)航向校準(zhǔn)警報(bào)顯示的位置管理器對(duì)象埠帕。
返回值 : 如果要允許顯示航向校準(zhǔn)警報(bào),則為“YES”玖绿;如果不允許敛瓷,則為“NO”。
航向校準(zhǔn)警報(bào)頁面大致長成這樣 :
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error;
函數(shù)描述 :通知代理位置管理器無法檢索位置值斑匪。位置管理器在嘗試獲取位置或標(biāo)題數(shù)據(jù)時(shí)遇到錯(cuò)誤時(shí)調(diào)用此方法呐籽。如果位置服務(wù)無法立即檢索位置,它將報(bào)告kclerRorrorLocationUnknown錯(cuò)誤并繼續(xù)嘗試蚀瘸。在這種情況下狡蝶,您可以忽略錯(cuò)誤并等待新事件。如果由于附近磁場的強(qiáng)烈干擾而無法確定航向贮勃,則此方法返回kCLErrorHeadingFailure贪惹。
如果用戶拒絕應(yīng)用程序使用位置服務(wù),則此方法將報(bào)告一個(gè)kCLErrorDenied錯(cuò)誤寂嘉。收到此類錯(cuò)誤后奏瞬,應(yīng)停止定位服務(wù)枫绅。
參數(shù) :
manager : 無法檢索位置的位置管理器對(duì)象。
error : 包含無法檢索位置或標(biāo)題的原因的錯(cuò)誤對(duì)象硼端。
- (void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLRegion *)region API_AVAILABLE(ios(4.0), macos(10.8)) API_UNAVAILABLE(watchos, tvOS);
函數(shù)描述 :通知代理用戶已進(jìn)入指定區(qū)域并淋。因?yàn)閰^(qū)域是共享的應(yīng)用程序資源,所以每個(gè)活動(dòng)位置管理器對(duì)象都將此消息傳遞給其關(guān)聯(lián)的代理珍昨。哪個(gè)位置管理器實(shí)際注冊(cè)了指定的區(qū)域并不重要县耽。如果多個(gè)位置管理器共享一個(gè)代理對(duì)象,則該代理將多次接收消息曼尊。所提供的區(qū)域?qū)ο罂赡芘c已注冊(cè)的區(qū)域?qū)ο蟛煌昃鳌R虼耍肋h(yuǎn)不要執(zhí)行對(duì)象指針級(jí)別的比較來確定是否相等骆撇。相反瞒御,使用該區(qū)域的標(biāo)識(shí)符字符串來確定您的代理是否應(yīng)該響應(yīng)。
參數(shù) :
manager : 報(bào)告事件的位置管理器對(duì)象神郊。
region : 包含所輸入?yún)^(qū)域信息的對(duì)象肴裙。
- (void)locationManager:(CLLocationManager *)manager
didExitRegion:(CLRegion *)region API_AVAILABLE(ios(4.0), macos(10.8)) API_UNAVAILABLE(watchos, tvOS);
函數(shù)描述 :通知代理用戶已離開指定區(qū)域。因?yàn)閰^(qū)域是共享的應(yīng)用程序資源涌乳,所以每個(gè)活動(dòng)位置管理器對(duì)象都將此消息傳遞給其關(guān)聯(lián)的代理蜻懦。哪個(gè)位置管理器實(shí)際注冊(cè)了指定的區(qū)域并不重要。如果多個(gè)位置管理器共享一個(gè)代理對(duì)象夕晓,則該代理將多次接收消息宛乃。所提供的區(qū)域?qū)ο罂赡芘c已注冊(cè)的區(qū)域?qū)ο蟛煌R虼苏袅荆肋h(yuǎn)不要執(zhí)行對(duì)象指針級(jí)別的比較來確定是否相等征炼。相反,使用該區(qū)域的標(biāo)識(shí)符字符串來確定您的代理是否應(yīng)該響應(yīng)躬贡。
參數(shù) :
manager : 報(bào)告事件的位置管理器對(duì)象谆奥。
region : 包含有關(guān)已離開區(qū)域的信息的對(duì)象。
- (void)locationManager:(CLLocationManager *)manager
didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region API_AVAILABLE(ios(7.0), macos(10.10)) API_UNAVAILABLE(watchos, tvOS);
函數(shù)描述 :通知代理指定區(qū)域的狀態(tài)拂玻。每當(dāng)區(qū)域有邊界轉(zhuǎn)換時(shí)酸些,位置管理器都會(huì)調(diào)用此方法。除了調(diào)用locationManager:didEnterRegion:和locationManager:didextregion:方法之外檐蚜,它還調(diào)用此方法魄懂。位置管理器還調(diào)用此方法以響應(yīng)對(duì)其requestStateForRegion:方法的調(diào)用,該方法異步運(yùn)行熬甚。
參數(shù) :
manager : 報(bào)告事件的位置管理器對(duì)象逢渔。
state : 指定區(qū)域的狀態(tài)。
region : 國家確定的地區(qū)乡括。
- (void)locationManager:(CLLocationManager *)manager
monitoringDidFailForRegion:(nullable CLRegion *)region
withError:(NSError *)error API_AVAILABLE(ios(4.0), macos(10.8)) API_UNAVAILABLE(watchos, tvOS);
函數(shù)描述 :通知代理發(fā)生區(qū)域監(jiān)視錯(cuò)誤肃廓。如果嘗試監(jiān)視給定區(qū)域時(shí)出錯(cuò),位置管理器會(huì)將此消息發(fā)送給其代理诲泌。區(qū)域監(jiān)視可能會(huì)失敗盲赊,因?yàn)闊o法監(jiān)視該區(qū)域本身,或者是因?yàn)樵谂渲脜^(qū)域監(jiān)視服務(wù)時(shí)出現(xiàn)了更常見的故障敷扫。
盡管此方法的實(shí)現(xiàn)是可選的哀蘑,但如果在應(yīng)用程序中使用區(qū)域監(jiān)視,建議實(shí)現(xiàn)它葵第。
參數(shù) :
manager : 報(bào)告事件的位置管理器對(duì)象绘迁。
region : 發(fā)生錯(cuò)誤的區(qū)域。
error : 一個(gè)錯(cuò)誤對(duì)象卒密,包含指示區(qū)域監(jiān)視失敗原因的錯(cuò)誤代碼缀台。
- (void)locationManager:(CLLocationManager *)manager
didStartMonitoringForRegion:(CLRegion *)region API_AVAILABLE(ios(5.0), macos(10.8)) API_UNAVAILABLE(watchos, tvOS);
函數(shù)描述 :通知代理正在監(jiān)視新區(qū)域。
參數(shù) :
manager : 報(bào)告事件的位置管理器對(duì)象哮奇。
region : 正在監(jiān)視的區(qū)域膛腐。
- (void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager API_AVAILABLE(ios(6.0)) API_UNAVAILABLE(watchos, tvos, macOS);
函數(shù)描述 :通知代理位置更新已暫停。當(dāng)位置管理器檢測(cè)到設(shè)備的位置沒有改變時(shí)鼎俘,它可以暫停更新的傳遞哲身,以便關(guān)閉相應(yīng)的硬件并節(jié)省電源。當(dāng)它這樣做時(shí)贸伐,它會(huì)調(diào)用此方法以讓應(yīng)用程序知道發(fā)生了這種情況勘天。
暫停發(fā)生后,必須在適當(dāng)?shù)臅r(shí)間重新啟動(dòng)位置服務(wù)捉邢「浚可以使用此方法的實(shí)現(xiàn)在用戶的當(dāng)前位置啟動(dòng)區(qū)域監(jiān)視,或啟用“訪問位置”服務(wù)來確定用戶何時(shí)開始再次移動(dòng)歌逢。另一種選擇是立即以較低的精度重新啟動(dòng)定位服務(wù)(這可以節(jié)省能源)巾钉,然后只有在用戶再次開始移動(dòng)后才能恢復(fù)較高的精度。
參數(shù) :
manager : 暫停事件傳遞的位置管理器對(duì)象秘案。
- (void)locationManagerDidResumeLocationUpdates:(CLLocationManager *)manager API_AVAILABLE(ios(6.0)) API_UNAVAILABLE(watchos, tvos, macOS);
函數(shù)描述 :通知代理位置更新的傳遞已恢復(fù)砰苍。當(dāng)在自動(dòng)暫停后重啟定位服務(wù)時(shí)哈雏,Core location會(huì)調(diào)用這個(gè)方法來通知你的應(yīng)用服務(wù)已經(jīng)恢復(fù)第焰。Core location不會(huì)在暫停更新后自動(dòng)恢復(fù)更新论矾,程序要負(fù)責(zé)重新啟動(dòng)你的應(yīng)用程序中的定位服務(wù)献酗。
參數(shù) :
manager : 恢復(fù)事件傳遞的位置管理器笔咽。
- (void)locationManager:(CLLocationManager *)manager
didFinishDeferredUpdatesWithError:(nullable NSError *)error API_AVAILABLE(ios(6.0), macos(10.9)) API_UNAVAILABLE(watchos, tvOS);
函數(shù)描述 :通知代理不再延遲更新长已。CLLocationManager對(duì)象調(diào)用此方法以讓應(yīng)用程序知道它已停止延遲位置事件的傳遞郎嫁。管理器可能出于多種原因調(diào)用此方法堕花。例如未舟,當(dāng)您完全停止位置更新圈暗、要求位置管理器禁止延遲更新或滿足延遲更新的條件(例如超過超時(shí)或距離參數(shù))時(shí)掂为,它將調(diào)用此函數(shù)。
參數(shù) :
manager : 生成更新事件的位置管理器對(duì)象员串。
error : 包含無法傳遞延遲位置更新原因的錯(cuò)誤對(duì)象勇哗。
CLGeocoder - 地理編碼
用于在地理坐標(biāo)和地名之間轉(zhuǎn)換的接口。提供在坐標(biāo)(指定為經(jīng)緯度)和該坐標(biāo)的地名之間進(jìn)行轉(zhuǎn)換的服務(wù)寸齐。坐標(biāo)的地名表示通常由與給定位置相對(duì)應(yīng)的街道欲诺、城市、州和國家信息組成渺鹦,但也可以包含相關(guān)的興趣點(diǎn)扰法、地標(biāo)或其他識(shí)別信息。geocoder對(duì)象是一個(gè)單一對(duì)象毅厚,它與基于網(wǎng)絡(luò)的服務(wù)一起查找指定坐標(biāo)值的地標(biāo)信息塞颁。
若要使用地理編碼器對(duì)象,請(qǐng)創(chuàng)建該對(duì)象并調(diào)用其正向或反向地理編碼方法之一以開始請(qǐng)求卧斟。反向地理編碼請(qǐng)求采用緯度和經(jīng)度值殴边,查找到用戶可讀的地址。正向地理編碼請(qǐng)求采用用戶可讀的地址珍语,并找到相應(yīng)的緯度和經(jīng)度值锤岸。正向地理編碼請(qǐng)求還可以返回有關(guān)指定位置的附加信息,例如該位置的興趣點(diǎn)或建筑物板乙。對(duì)于這兩種類型的請(qǐng)求是偷,使用CLPlacemark對(duì)象返回結(jié)果。在正向地理編碼請(qǐng)求的情況下募逞,如果提供的信息產(chǎn)生多個(gè)可能的位置蛋铆,則可以返回多個(gè)placemark對(duì)象。為了明智地決定返回什么類型的信息放接,geocoder服務(wù)器在處理請(qǐng)求時(shí)使用提供給它的所有信息刺啦。例如,如果用戶在高速公路上快速移動(dòng)纠脾,它可能返回整個(gè)區(qū)域的名稱玛瘸,而不是用戶經(jīng)過的小公園的名稱。
CLGeocoder常用函數(shù)
- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
函數(shù)描述 :為指定的位置提交反向地理編碼請(qǐng)求苟蹈,此方法將指定的位置數(shù)據(jù)異步提交給地理編碼服務(wù)器并返回糊渊。當(dāng)請(qǐng)求完成時(shí),geocoder在主線程上執(zhí)行提供的完成處理程序慧脱。
啟動(dòng)反向地理編碼請(qǐng)求后渺绒,不要嘗試啟動(dòng)另一個(gè)反向或正向地理編碼請(qǐng)求。地理編碼請(qǐng)求對(duì)每個(gè)應(yīng)用程序都有速率限制,因此在短時(shí)間內(nèi)發(fā)出太多請(qǐng)求可能會(huì)導(dǎo)致某些請(qǐng)求失敗宗兼。當(dāng)超過最大速率時(shí)躏鱼,geocoder會(huì)將值為kCLErrorNetwork的錯(cuò)誤對(duì)象傳遞給完成處理程序。
參數(shù) :
location : 包含要查找的坐標(biāo)數(shù)據(jù)的位置對(duì)象针炉。
completionHandler : 要與結(jié)果一起執(zhí)行的處理程序塊挠他。無論請(qǐng)求是成功還是失敗扳抽,geocoder都會(huì)執(zhí)行此處理程序篡帕。
- (void)reverseGeocodeLocation:(CLLocation *)location preferredLocale:(nullable NSLocale *)locale completionHandler:(CLGeocodeCompletionHandler)completionHandler API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));
函數(shù)描述 :提交指定位置和區(qū)域設(shè)置的反向地理編碼請(qǐng)求。此方法將指定的位置數(shù)據(jù)異步提交給地理編碼服務(wù)器并返回贸呢。當(dāng)請(qǐng)求完成時(shí)镰烧,geocoder在主線程上執(zhí)行提供的完成處理程序。
啟動(dòng)反向地理編碼請(qǐng)求后楞陷,不要嘗試啟動(dòng)另一個(gè)反向或正向地理編碼請(qǐng)求怔鳖。地理編碼請(qǐng)求對(duì)每個(gè)應(yīng)用程序都有速率限制,因此在短時(shí)間內(nèi)發(fā)出太多請(qǐng)求可能會(huì)導(dǎo)致某些請(qǐng)求失敗固蛾。當(dāng)超過最大速率時(shí)结执,geocoder會(huì)將帶有值network的錯(cuò)誤對(duì)象傳遞給完成處理程序。
參數(shù) :
location : 包含要查找的坐標(biāo)數(shù)據(jù)的位置對(duì)象艾凯。
locale : 返回地址信息時(shí)要使用的區(qū)域設(shè)置献幔。如果希望在不同于用戶當(dāng)前語言設(shè)置的區(qū)域設(shè)置中返回地址,可以為此參數(shù)指定一個(gè)值趾诗。指定nil以使用用戶的默認(rèn)區(qū)域設(shè)置信息蜡感。
completionHandler : 要與結(jié)果一起執(zhí)行的處理程序塊。無論請(qǐng)求是成功還是失敗恃泪,geocoder都會(huì)執(zhí)行此處理程序郑兴。
- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
函數(shù)描述 :使用指定的字符串提交正向地理編碼請(qǐng)求。此方法將指定的位置數(shù)據(jù)異步提交給地理編碼服務(wù)器并返回贝乎。完成處理程序塊將在主線程上執(zhí)行情连。
啟動(dòng)前向地理編碼請(qǐng)求后,不要嘗試啟動(dòng)另一個(gè)前向或反向地理編碼請(qǐng)求览效。地理編碼請(qǐng)求對(duì)每個(gè)應(yīng)用程序都有速率限制却舀,因此在短時(shí)間內(nèi)發(fā)出太多請(qǐng)求可能會(huì)導(dǎo)致某些請(qǐng)求失敗。當(dāng)超過最大速率時(shí)朽肥,geocoder會(huì)將值為kCLErrorNetwork的錯(cuò)誤對(duì)象傳遞給完成處理程序禁筏。
參數(shù) :
addressString : 描述要查找的位置的字符串。
completionHandler : 要與結(jié)果一起執(zhí)行的處理程序塊衡招。無論請(qǐng)求是成功還是失敗篱昔,geocoder都會(huì)執(zhí)行此處理程序。
- (void)geocodeAddressString:(NSString *)addressString inRegion:(nullable CLRegion *)region completionHandler:(CLGeocodeCompletionHandler)completionHandler;
函數(shù)描述 :使用指定的字符串和區(qū)域信息提交正向地理編碼請(qǐng)求。此方法將指定的位置數(shù)據(jù)異步提交給地理編碼服務(wù)器并返回州刽。完成處理程序塊將在主線程上執(zhí)行空执。
啟動(dòng)前向地理編碼請(qǐng)求后,不要嘗試啟動(dòng)另一個(gè)前向或反向地理編碼請(qǐng)求穗椅。地理編碼請(qǐng)求對(duì)每個(gè)應(yīng)用程序都有速率限制辨绊,因此在短時(shí)間內(nèi)發(fā)出太多請(qǐng)求可能會(huì)導(dǎo)致某些請(qǐng)求失敗。當(dāng)超過最大速率時(shí)匹表,geocoder會(huì)將值為kCLErrorNetwork的錯(cuò)誤對(duì)象傳遞給完成處理程序门坷。
參數(shù) :
addressString : 描述要查找的位置的字符串。
region : 查找指定地址時(shí)用作提示的地理區(qū)域袍镀。通過指定一個(gè)區(qū)域默蚌,可以將返回的結(jié)果集的優(yōu)先級(jí)設(shè)置為靠近某個(gè)特定地理區(qū)域(通常是用戶的當(dāng)前位置)的位置。如果應(yīng)用程序被授權(quán)提供位置服務(wù)苇羡,并且您為此參數(shù)指定了nil绸吸,則結(jié)果集將根據(jù)用戶的大致位置進(jìn)行優(yōu)先級(jí)排序。調(diào)用此方法不會(huì)觸發(fā)位置服務(wù)授權(quán)請(qǐng)求设江。
completionHandler : 要與結(jié)果一起執(zhí)行的處理程序塊锦茁。無論請(qǐng)求是成功還是失敗,geocoder都會(huì)執(zhí)行此處理程序叉存。
- (void)geocodeAddressString:(NSString *)addressString inRegion:(nullable CLRegion *)region preferredLocale:(nullable NSLocale *)locale completionHandler:(CLGeocodeCompletionHandler)completionHandler API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));
函數(shù)描述 :使用指定的地址字符串和區(qū)域設(shè)置信息提交正向地理編碼請(qǐng)求码俩。此方法將指定的位置數(shù)據(jù)異步提交給地理編碼服務(wù)器并返回。當(dāng)請(qǐng)求完成時(shí)鹉胖,geocoder在主線程上執(zhí)行提供的完成處理程序握玛。
啟動(dòng)正向地理編碼請(qǐng)求后,不要嘗試啟動(dòng)另一個(gè)反向或正向地理編碼請(qǐng)求甫菠。地理編碼請(qǐng)求對(duì)每個(gè)應(yīng)用程序都有速率限制挠铲,因此在短時(shí)間內(nèi)發(fā)出太多請(qǐng)求可能會(huì)導(dǎo)致某些請(qǐng)求失敗。當(dāng)超過最大速率時(shí)寂诱,geocoder會(huì)將帶有值network的錯(cuò)誤對(duì)象傳遞給完成處理程序拂苹。
參數(shù) :
addressString : 描述要查找的位置的字符串。
region : 查找指定地址時(shí)用作提示的地理區(qū)域痰洒。通過指定一個(gè)區(qū)域瓢棒,可以將返回的結(jié)果集的優(yōu)先級(jí)設(shè)置為靠近某個(gè)特定地理區(qū)域(通常是用戶的當(dāng)前位置)的位置。如果應(yīng)用程序被授權(quán)提供位置服務(wù)丘喻,并且您為此參數(shù)指定了nil脯宿,則結(jié)果集將根據(jù)用戶的大致位置進(jìn)行優(yōu)先級(jí)排序。調(diào)用此方法不會(huì)觸發(fā)位置服務(wù)授權(quán)請(qǐng)求泉粉。
locale : 地址字符串的區(qū)域設(shè)置连霉。指定nil以使用用戶的當(dāng)前區(qū)域設(shè)置榴芳。
completionHandler : 要與結(jié)果一起執(zhí)行的處理程序塊。無論請(qǐng)求是成功還是失敗跺撼,geocoder都會(huì)執(zhí)行此處理程序窟感。
- (void)cancelGeocode;
函數(shù)描述 :取消掛起的地理編碼請(qǐng)求∏妇可以使用此方法取消掛起的請(qǐng)求并釋放與該請(qǐng)求關(guān)聯(lián)的資源柿祈。取消掛起的請(qǐng)求將導(dǎo)致調(diào)用完成處理程序塊。如果請(qǐng)求未掛起哩至,因?yàn)樗逊祷鼗蛏形撮_始躏嚎,則此方法不執(zhí)行任何操作。
//
// CLLocation+YCLocation.h
// YCMapViewDemo
//
// Created by gongliang on 13-9-16.
// Copyright (c) 2013年 gongliang. All rights reserved.
// 火星坐標(biāo)系轉(zhuǎn)換擴(kuò)展
/*
從 CLLocationManager 取出來的經(jīng)緯度放到 mapView 上顯示憨募,是錯(cuò)誤的!
從 CLLocationManager 取出來的經(jīng)緯度去 Google Maps API 做逆地址解析紧索,當(dāng)然是錯(cuò)的!
從 MKMapView 取出來的經(jīng)緯度去 Google Maps API 做逆地址解析終于對(duì)了菜谣。去百度地圖API做逆地址解析,依舊是錯(cuò)的晚缩!
從上面兩處取的經(jīng)緯度放到百度地圖上顯示都是錯(cuò)的尾膊!錯(cuò)的!的荞彼!
分為 地球坐標(biāo)冈敛,火星坐標(biāo)(iOS mapView 高德 , 國內(nèi)google, 搜搜鸣皂、阿里云 都是火星坐標(biāo))抓谴,百度坐標(biāo)(百度地圖數(shù)據(jù)主要都是四維圖新提供的)
火星坐標(biāo): MKMapView
地球坐標(biāo): CLLocationManager
當(dāng)用到CLLocationManager 得到的數(shù)據(jù)轉(zhuǎn)化為火星坐標(biāo), MKMapView不用處理
API 坐標(biāo)系
百度地圖API 百度坐標(biāo)
騰訊搜搜地圖API 火星坐標(biāo)
搜狐搜狗地圖API 搜狗坐標(biāo)
阿里云地圖API 火星坐標(biāo)
圖吧MapBar地圖API 圖吧坐標(biāo)
高德MapABC地圖API 火星坐標(biāo)
靈圖51ditu地圖API 火星坐標(biāo)
*/
#import <CoreLocation/CoreLocation.h>
@interface CLLocation (YCLocation)
///從地圖坐標(biāo)轉(zhuǎn)化到火星坐標(biāo)
- (CLLocation*)locationMarsFromEarth;
///從火星坐標(biāo)轉(zhuǎn)化到百度坐標(biāo)
- (CLLocation*)locationBaiduFromMars;
///從百度坐標(biāo)到火星坐標(biāo)
- (CLLocation*)locationMarsFromBaidu;
@end
//
// CLLocation+YCLocation.m
// YCMapViewDemo
//
// Created by gongliang on 13-9-16.
// Copyright (c) 2013年 gongliang. All rights reserved.
//
#import "CLLocation+YCLocation.h"
void transform_earth_from_mars(double lat, double lng, double* tarLat, double* tarLng);
void transform_mars_from_baidu(double lat, double lng, double* tarLat, double* tarLng);
void transform_baidu_from_mars(double lat, double lng, double* tarLat, double* tarLng);
@implementation CLLocation (YCLocation)
///從地圖坐標(biāo)轉(zhuǎn)化到火星坐標(biāo)
- (CLLocation*)locationMarsFromEarth
{
double lat = 0.0;
double lng = 0.0;
transform_earth_from_mars(self.coordinate.latitude, self.coordinate.longitude, &lat, &lng);
return [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(lat, lng)
altitude:self.altitude
horizontalAccuracy:self.horizontalAccuracy
verticalAccuracy:self.verticalAccuracy
course:self.course
speed:self.speed
timestamp:self.timestamp];
}
///從火星坐標(biāo)轉(zhuǎn)化到百度坐標(biāo)
- (CLLocation*)locationBaiduFromMars
{
double lat = 0.0;
double lng = 0.0;
transform_mars_from_baidu(self.coordinate.latitude, self.coordinate.longitude, &lat, &lng);
return [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(lat, lng)
altitude:self.altitude
horizontalAccuracy:self.horizontalAccuracy
verticalAccuracy:self.verticalAccuracy
course:self.course
speed:self.speed
timestamp:self.timestamp];
}
///從百度坐標(biāo)到火星坐標(biāo)
- (CLLocation*)locationMarsFromBaidu
{
double lat = 0.0;
double lng = 0.0;
transform_baidu_from_mars(self.coordinate.latitude, self.coordinate.longitude, &lat, &lng);
return [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(lat, lng)
altitude:self.altitude
horizontalAccuracy:self.horizontalAccuracy
verticalAccuracy:self.verticalAccuracy
course:self.course
speed:self.speed
timestamp:self.timestamp];
}
- (CLLocation*)locationEarthFromMars
{
// 二分法查糾偏文件
// http://xcodev.com/131.html
return nil;
}
@end
// --- transform_earth_from_mars ---
// 參考來源:https://on4wp7.codeplex.com/SourceControl/changeset/view/21483#353936
// Krasovsky 1940
//
// a = 6378245.0, 1/f = 298.3
// b = a * (1 - f)
// ee = (a^2 - b^2) / a^2;
const double a = 6378245.0;
const double ee = 0.00669342162296594323;
bool transform_sino_out_china(double lat, double lon)
{
if (lon < 72.004 || lon > 137.8347)
return true;
if (lat < 0.8293 || lat > 55.8271)
return true;
return false;
}
double transform_earth_from_mars_lat(double x, double y)
{
double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(fabs(x));
ret += (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0;
ret += (20.0 * sin(y * M_PI) + 40.0 * sin(y / 3.0 * M_PI)) * 2.0 / 3.0;
ret += (160.0 * sin(y / 12.0 * M_PI) + 320 * sin(y * M_PI / 30.0)) * 2.0 / 3.0;
return ret;
}
double transform_earth_from_mars_lng(double x, double y)
{
double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(fabs(x));
ret += (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0;
ret += (20.0 * sin(x * M_PI) + 40.0 * sin(x / 3.0 * M_PI)) * 2.0 / 3.0;
ret += (150.0 * sin(x / 12.0 * M_PI) + 300.0 * sin(x / 30.0 * M_PI)) * 2.0 / 3.0;
return ret;
}
void transform_earth_from_mars(double lat, double lng, double* tarLat, double* tarLng)
{
if (transform_sino_out_china(lat, lng))
{
*tarLat = lat;
*tarLng = lng;
return;
}
double dLat = transform_earth_from_mars_lat(lng - 105.0, lat - 35.0);
double dLon = transform_earth_from_mars_lng(lng - 105.0, lat - 35.0);
double radLat = lat / 180.0 * M_PI;
double magic = sin(radLat);
magic = 1 - ee * magic * magic;
double sqrtMagic = sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * M_PI);
dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * M_PI);
*tarLat = lat + dLat;
*tarLng = lng + dLon;
}
// --- transform_earth_from_mars end ---
// --- transform_mars_vs_bear_paw ---
// 參考來源:http://blog.woodbunny.com/post-68.html
const double x_pi = M_PI * 3000.0 / 180.0;
void transform_mars_from_baidu(double gg_lat, double gg_lon, double *bd_lat, double *bd_lon)
{
double x = gg_lon, y = gg_lat;
double z = sqrt(x * x + y * y) + 0.00002 * sin(y * x_pi);
double theta = atan2(y, x) + 0.000003 * cos(x * x_pi);
*bd_lon = z * cos(theta) + 0.0065;
*bd_lat = z * sin(theta) + 0.006;
}
void transform_baidu_from_mars(double bd_lat, double bd_lon, double *gg_lat, double *gg_lon)
{
double x = bd_lon - 0.0065, y = bd_lat - 0.006;
double z = sqrt(x * x + y * y) - 0.00002 * sin(y * x_pi);
double theta = atan2(y, x) - 0.000003 * cos(x * x_pi);
*gg_lon = z * cos(theta);
*gg_lat = z * sin(theta);
}
//
// TestCLLocationController.h
// FrameworksTest
#import <UIKit/UIKit.h>
@interface TestCLLocationController : UIViewController
@end
//
// TestCLLocationController.m
// FrameworksTest
#import "TestCLLocationController.h"
#import "CLLocation+YCLocation.h"
@interface TestCLLocationController ()<CLLocationManagerDelegate>
@property (nonatomic, strong) CLLocationManager *locationManager;//位置管理對(duì)象
@property (nonatomic, strong) CLLocation *location;//位置對(duì)象
@property (nonatomic, strong) UIImageView *headingRelatedImageView;//航向指示視圖
@property (nonatomic, strong) UITextField *addressTextField;//地址文本輸入框
@property (nonatomic, strong) UILabel *longitudeLabel;//經(jīng)度值標(biāo)簽
@property (nonatomic, strong) UILabel *latitudeLabel;//緯度值標(biāo)簽
@property (nonatomic, strong) UITextField *longitudeTextField;//經(jīng)度文本輸入框
@property (nonatomic, strong) UITextField *latitudeTextField;//緯度文本輸入框
@property (nonatomic, strong) UILabel *addressLabel;//具體地址標(biāo)簽
@property (nonatomic, strong) UILabel *regionMonitorLabel;//區(qū)域監(jiān)視標(biāo)簽
@property (nonatomic, strong) UILabel *monitoringLabel;//正在區(qū)域監(jiān)視標(biāo)簽
@property (nonatomic, strong) UILabel *locationUpdateLabel;//位置更新標(biāo)簽
@end
@implementation TestCLLocationController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self createNavigationTitleView:@"CLLocation"];
//請(qǐng)求定位權(quán)限
[self requestLocationJurisdiction];
//設(shè)置航向指示視圖
[self setHeadingRelatedView];
//設(shè)置區(qū)域監(jiān)聽
[self setAreaMonitoring];
//設(shè)置視圖
[self createView];
}
///請(qǐng)求定位權(quán)限
- (void)requestLocationJurisdiction{
//判斷設(shè)備在設(shè)置中是否啟用了位置服務(wù)
if([CLLocationManager locationServicesEnabled]){
//設(shè)備啟用了位置服務(wù)癌压,判斷應(yīng)用程序的位置權(quán)限
switch ([CLLocationManager authorizationStatus]) {
//用戶尚未選擇應(yīng)用程序是否可以使用位置服務(wù)
case kCLAuthorizationStatusNotDetermined:
//啟用定位
[self enablePositioning];
//請(qǐng)求在應(yīng)用程序位于前臺(tái)時(shí)使用定位服務(wù)的權(quán)限
[self.locationManager requestWhenInUseAuthorization];
break;
//用戶授權(quán)應(yīng)用程序隨時(shí)啟動(dòng)定位服務(wù)的權(quán)限
//用戶已授權(quán)僅在使用應(yīng)用程序時(shí)有訪問位置的權(quán)限
case kCLAuthorizationStatusAuthorizedAlways:
case kCLAuthorizationStatusAuthorizedWhenInUse:
//啟用定位
[self enablePositioning];
break;
//拒絕對(duì)此應(yīng)用程序的位置授權(quán)
case kCLAuthorizationStatusDenied:
//設(shè)備未啟用位置服務(wù),展示提示
[self showPermissionSettingAlert:@"無法定位" withMessage:@"當(dāng)前應(yīng)用程序設(shè)置不支持定位"];
break;
default:
break;
}
}else{
//設(shè)備未啟用位置服務(wù)稚新,展示提示
[self showPermissionSettingAlert:@"無法定位" withMessage:@"當(dāng)前設(shè)備設(shè)置不支持定位"];
}
}
///啟用定位
- (void)enablePositioning{
//初始化位置管理對(duì)象
if(self.locationManager == nil){
self.locationManager = [[CLLocationManager alloc]init];
}
//設(shè)置代理
self.locationManager.delegate = self;
//請(qǐng)求在應(yīng)用程序位于前臺(tái)時(shí)使用定位服務(wù)的權(quán)限
[self.locationManager requestAlwaysAuthorization];
//開始生成報(bào)告用戶當(dāng)前位置的更新
[self.locationManager startUpdatingLocation];
//判斷位置管理器是否能夠生成與導(dǎo)航方向相關(guān)的事件
if ([CLLocationManager headingAvailable]) {
//生成新航向事件所需的最小角度變化
self.locationManager.headingFilter = kCLHeadingFilterNone;
[self.locationManager startUpdatingHeading];
}
}
///顯示權(quán)限設(shè)置提示框
- (void)showPermissionSettingAlert:(NSString *)title withMessage:(NSString *)message{
//初始化提示框
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
//YES操作項(xiàng)
UIAlertAction *yesAction = [UIAlertAction actionWithTitle:@"YES" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
//打開設(shè)置頁面
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]options:@{}completionHandler:nil];
}];
//NO操作項(xiàng)
UIAlertAction *noAction = [UIAlertAction actionWithTitle:@"NO" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
}];
[alertController addAction:yesAction];
[alertController addAction:noAction];
[self presentViewController:alertController animated:true completion:nil];
}
///設(shè)置航向指示視圖
- (void)setHeadingRelatedView{
//航向指示視圖
self.headingRelatedImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"btn_navigation"]];
self.headingRelatedImageView.contentMode = UIViewContentModeScaleToFill;
[self.view addSubview:self.headingRelatedImageView];
//Masonry布局
[self.headingRelatedImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.view.mas_top).offset(HEAD_BAR_HEIGHT);
make.centerX.equalTo(self.view);
make.size.mas_equalTo(CGSizeMake(20, 30));
}];
}
///設(shè)置區(qū)域監(jiān)聽
- (void)setAreaMonitoring{
//判斷設(shè)備是否支持區(qū)域監(jiān)聽
if (![CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]]) {
return;
}
//指定區(qū)域類型,一般是圓形區(qū)域
//區(qū)域的中點(diǎn)坐標(biāo)
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(39.909502, 119.511151);
//區(qū)域半徑(米)
CLLocationDistance distance = 170.0;
//半徑限制
if (distance > self.locationManager.maximumRegionMonitoringDistance) {
distance = self.locationManager.maximumRegionMonitoringDistance;
}
//初始化圓形地理區(qū)域,指定為中心點(diǎn)和半徑决记。
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:distance identifier:@"MyLocation"];
//開始監(jiān)視指定區(qū)域往枷,對(duì)于要監(jiān)視的每個(gè)區(qū)域忱叭,必須調(diào)用此方法一次
[self.locationManager startMonitoringForRegion:region];
//延遲2秒執(zhí)行今艺,以防止概率出現(xiàn)的Domain=kCLErrorDomain Code=5錯(cuò)誤
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC));
dispatch_after(delayTime, dispatch_get_main_queue(), ^{
//異步檢索區(qū)域的狀態(tài)
[self.locationManager requestStateForRegion:region];
});
}
///設(shè)置視圖
- (void)createView{
//初始化地址提示標(biāo)簽
UILabel *addressTipsLabel = [[UILabel alloc]initWithFrame:CGRectZero];
addressTipsLabel.text = @"地址:";
addressTipsLabel.font = [UIFont systemFontOfSize:15];
[self.view addSubview:addressTipsLabel];
//Masonry布局
[addressTipsLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.headingRelatedImageView.mas_bottom).offset(20);
make.left.equalTo(self.view.mas_left).offset(20);
}];
//初始化地址文本輸入框
self.addressTextField = [[UITextField alloc]initWithFrame:CGRectZero];
self.addressTextField.placeholder = @" 請(qǐng)輸入地址";
self.addressTextField.layer.borderColor = [UIColor blackColor].CGColor;
self.addressTextField.layer.borderWidth = 0.5;
[self.view addSubview:self.addressTextField];
//Masonry布局
[self.addressTextField mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(addressTipsLabel);
make.left.equalTo(addressTipsLabel.mas_right).offset(10);
make.size.mas_equalTo(CGSizeMake(200, 35));
}];
//初始化查詢按鈕
UIButton *queryButton = [UIButton buttonWithType:UIButtonTypeCustom];
[queryButton setTitle:@"查詢" forState:UIControlStateNormal];
[queryButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[queryButton setBackgroundColor:[UIColor blueColor]];
[queryButton setTag:1000];
[self.view addSubview:queryButton];
[queryButton addTarget:self action:@selector(queryButtonClick:) forControlEvents:UIControlEventTouchUpInside];
//Masonry布局
[queryButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.addressTextField);
make.left.equalTo(self.addressTextField.mas_right).offset(10);
make.size.mas_equalTo(CGSizeMake(60, 35));
}];
//初始化經(jīng)度值標(biāo)簽
self.longitudeLabel = [[UILabel alloc]initWithFrame:CGRectZero];
self.longitudeLabel.font = [UIFont systemFontOfSize:15];
self.longitudeLabel.textColor = [UIColor redColor];
self.longitudeLabel.textAlignment = NSTextAlignmentCenter;
self.longitudeLabel.text = @"當(dāng)前經(jīng)度";
self.longitudeLabel.layer.borderWidth = 0.5;
self.longitudeLabel.layer.borderColor = [UIColor redColor].CGColor;
[self.view addSubview:self.longitudeLabel];
[self.longitudeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(addressTipsLabel.mas_bottom).offset(30);
make.left.equalTo(self.view.mas_left).offset(20);
make.size.mas_equalTo(CGSizeMake(150, 30));
}];
//初始化緯度值標(biāo)簽
self.latitudeLabel = [[UILabel alloc]initWithFrame:CGRectZero];
self.latitudeLabel.font = [UIFont systemFontOfSize:15];
self.latitudeLabel.textColor = [UIColor greenColor];
self.latitudeLabel.text = @"當(dāng)前緯度";
self.latitudeLabel.textAlignment = NSTextAlignmentCenter;
self.latitudeLabel.layer.borderWidth = 0.5;
self.latitudeLabel.layer.borderColor = [UIColor greenColor].CGColor;
[self.view addSubview:self.latitudeLabel];
[self.latitudeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.longitudeLabel);
make.right.equalTo(queryButton.mas_right).offset(10);
make.size.mas_equalTo(CGSizeMake(150, 30));
}];
//初始化經(jīng)度提示標(biāo)簽
UILabel *longitudeTipsLabel = [[UILabel alloc]initWithFrame:CGRectZero];
longitudeTipsLabel.text = @"經(jīng)度:";
longitudeTipsLabel.font = [UIFont systemFontOfSize:15];
[self.view addSubview:longitudeTipsLabel];
//Masonry布局
[longitudeTipsLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.longitudeLabel.mas_bottom).offset(50);
make.left.equalTo(self.view.mas_left).offset(20);
}];
//初始化經(jīng)度文本輸入框
self.longitudeTextField = [[UITextField alloc]initWithFrame:CGRectZero];
self.longitudeTextField.placeholder = @" 請(qǐng)輸入經(jīng)度";
self.longitudeTextField.layer.borderColor = [UIColor blackColor].CGColor;
self.longitudeTextField.layer.borderWidth = 0.5;
[self.view addSubview:self.longitudeTextField];
//Masonry布局
[self.longitudeTextField mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(longitudeTipsLabel);
make.left.equalTo(addressTipsLabel.mas_right).offset(10);
make.size.mas_equalTo(CGSizeMake(105, 35));
}];
//初始化緯度提示標(biāo)簽
UILabel *latitudeTipsLabel = [[UILabel alloc]initWithFrame:CGRectZero];
latitudeTipsLabel.text = @"緯度:";
latitudeTipsLabel.font = [UIFont systemFontOfSize:15];
[self.view addSubview:latitudeTipsLabel];
//Masonry布局
[latitudeTipsLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(longitudeTipsLabel);
make.left.equalTo(self.latitudeLabel.mas_left);
}];
//初始化經(jīng)度文本輸入框
self.latitudeTextField = [[UITextField alloc]initWithFrame:CGRectZero];
self.latitudeTextField.placeholder = @" 請(qǐng)輸入緯度";
self.latitudeTextField.layer.borderColor = [UIColor blackColor].CGColor;
self.latitudeTextField.layer.borderWidth = 0.5;
[self.view addSubview:self.latitudeTextField];
//Masonry布局
[self.latitudeTextField mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(latitudeTipsLabel);
make.left.equalTo(latitudeTipsLabel.mas_right).offset(10);
make.size.mas_equalTo(CGSizeMake(105, 35));
}];
//初始化查詢按鈕
UIButton *queryButton2 = [UIButton buttonWithType:UIButtonTypeCustom];
[queryButton2 setTitle:@"查詢" forState:UIControlStateNormal];
[queryButton2 setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[queryButton2 setBackgroundColor:[UIColor blueColor]];
[queryButton2 setTag:1001];
[self.view addSubview:queryButton2];
[queryButton2 addTarget:self action:@selector(queryButtonClick:) forControlEvents:UIControlEventTouchUpInside];
//Masonry布局
[queryButton2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.longitudeTextField.mas_bottom).offset(20);
make.centerX.equalTo(self.view);
make.size.mas_equalTo(CGSizeMake(120, 35));
}];
//初始化具體地址標(biāo)簽
self.addressLabel = [[UILabel alloc]initWithFrame:CGRectZero];
self.addressLabel.font = [UIFont systemFontOfSize:15];
self.addressLabel.textColor = [UIColor redColor];
self.addressLabel.textAlignment = NSTextAlignmentCenter;
self.addressLabel.text = @"當(dāng)前位置:";
self.addressLabel.layer.borderWidth = 0.5;
self.addressLabel.layer.borderColor = [UIColor redColor].CGColor;
[self.view addSubview:self.addressLabel];
//Masonry布局
[self.addressLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(queryButton2.mas_bottom).offset(20);
make.left.equalTo(self.longitudeLabel.mas_left);
make.right.equalTo(self.latitudeLabel.mas_right);
make.height.mas_equalTo(30);
}];
//初始化區(qū)域監(jiān)視標(biāo)簽
self.regionMonitorLabel = [[UILabel alloc]initWithFrame:CGRectZero];
self.regionMonitorLabel.font = [UIFont systemFontOfSize:15];
self.regionMonitorLabel.textColor = [UIColor blackColor];
self.regionMonitorLabel.textAlignment = NSTextAlignmentCenter;
self.regionMonitorLabel.numberOfLines = 0;
self.regionMonitorLabel.layer.borderWidth = 0.5;
self.regionMonitorLabel.layer.borderColor = [UIColor blackColor].CGColor;
[self.view addSubview:self.regionMonitorLabel];
//Masonry布局
[self.regionMonitorLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.addressLabel.mas_bottom).offset(30);
make.left.equalTo(self.longitudeLabel.mas_left);
make.right.equalTo(self.view.mas_right).offset(- 20);
}];
//初始化正在區(qū)域監(jiān)視標(biāo)簽
self.monitoringLabel = [[UILabel alloc]initWithFrame:CGRectZero];
self.monitoringLabel.font = [UIFont systemFontOfSize:15];
self.monitoringLabel.textColor = [UIColor blackColor];
self.monitoringLabel.textAlignment = NSTextAlignmentCenter;
self.monitoringLabel.numberOfLines = 0;
self.monitoringLabel.layer.borderWidth = 0.5;
self.monitoringLabel.layer.borderColor = [UIColor blackColor].CGColor;
[self.view addSubview:self.monitoringLabel];
//Masonry布局
[self.monitoringLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.regionMonitorLabel.mas_bottom).offset(30);
make.left.equalTo(self.longitudeLabel.mas_left);
make.right.equalTo(self.view.mas_right).offset(- 20);
}];
//初始化位置更新標(biāo)簽
self.locationUpdateLabel = [[UILabel alloc]initWithFrame:CGRectZero];
self.locationUpdateLabel.font = [UIFont systemFontOfSize:15];
self.locationUpdateLabel.textColor = [UIColor blackColor];
self.locationUpdateLabel.textAlignment = NSTextAlignmentCenter;
self.locationUpdateLabel.numberOfLines = 0;
self.locationUpdateLabel.layer.borderWidth = 0.5;
self.locationUpdateLabel.layer.borderColor = [UIColor blackColor].CGColor;
[self.view addSubview:self.locationUpdateLabel];
//Masonry布局
[self.locationUpdateLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.monitoringLabel.mas_bottom).offset(30);
make.left.equalTo(self.longitudeLabel.mas_left);
make.right.equalTo(self.view.mas_right).offset(- 20);
}];
}
///查詢按鈕點(diǎn)擊事件
- (void)queryButtonClick:(UIButton *)sender{
if(sender.tag == 1000 ){
//初始化地理編碼器對(duì)象
CLGeocoder *geoCoder = [[CLGeocoder alloc]init];
//提交指定位置的正向地理編碼請(qǐng)求
[geoCoder geocodeAddressString:self.addressTextField.text completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
if (placemarks.count >0) {
CLPlacemark *placeMark = placemarks[0];
CLLocation *location = placeMark.location;
//設(shè)置經(jīng)度值標(biāo)簽的經(jīng)度
self.longitudeLabel.text = [NSString stringWithFormat:@"當(dāng)前經(jīng)度:%f",location.coordinate.longitude];
//設(shè)置維度值標(biāo)簽的緯度
self.latitudeLabel.text = [NSString stringWithFormat:@"當(dāng)前緯度:%f",location.coordinate.latitude];
}else if(error == nil && placemarks.count){
NSLog(@"無位置和錯(cuò)誤返回");
self.longitudeLabel.text = @"未找到";
self.latitudeLabel.text = @"未找到";
}else if(error){
NSLog(@"loction error:%@",error);
self.longitudeLabel.text = @"未找到";
self.latitudeLabel.text = @"未找到";
}
}];
}else if(sender.tag == 1001){
if(IS_NOT_EMPTY(self.longitudeTextField.text) && IS_NOT_EMPTY(self.latitudeTextField.text)){
CLLocationDegrees latitude = self.latitudeTextField.text.doubleValue;
CLLocationDegrees longitude = self.longitudeTextField.text.doubleValue;
self.location = [[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
}
//初始化地理編碼器對(duì)象
CLGeocoder *geoCoder = [[CLGeocoder alloc]init];
//提交指定位置的反向地理編碼請(qǐng)求
[geoCoder reverseGeocodeLocation:self.location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
if (placemarks.count >0) {
CLPlacemark *placeMark = placemarks[0];
NSLog(@"當(dāng)前國家 - %@",placeMark.country);//當(dāng)前國家
NSLog(@"當(dāng)前城市 - %@",placeMark.locality);//當(dāng)前城市
NSLog(@"當(dāng)前位置 - %@",placeMark.subLocality);//當(dāng)前位置
NSLog(@"當(dāng)前街道 - %@",placeMark.thoroughfare);//當(dāng)前街道
NSLog(@"具體地址 - %@",placeMark.name);//具體地址
self.addressLabel.text = [NSString stringWithFormat:@"%@%@%@,%@",IS_NOT_EMPTY(placeMark.locality)? placeMark.locality : @"",IS_NOT_EMPTY(placeMark.subLocality)? placeMark.subLocality : @"" ,IS_NOT_EMPTY(placeMark.thoroughfare)? placeMark.thoroughfare : @"",IS_NOT_EMPTY(placeMark.name)? placeMark.name : @""];
}else if(error == nil && placemarks.count){
NSLog(@"無位置和錯(cuò)誤返回");
}else if(error){
NSLog(@"loction error:%@",error);
}
}];
}
}
#pragma mark - CLLocationManagerDelegate
///通知代理新的位置數(shù)據(jù)可用
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
self.location = [locations lastObject];
if (self.location.coordinate.latitude <= 0 || self.location.coordinate.longitude <= 0) {
return;
}
CLLocationCoordinate2D locationCoordinate = self.location.coordinate;
//設(shè)置經(jīng)度值標(biāo)簽的經(jīng)度
self.longitudeLabel.text = [NSString stringWithFormat:@"當(dāng)前經(jīng)度:%f",locationCoordinate.longitude];
//設(shè)置維度值標(biāo)簽的緯度
self.latitudeLabel.text = [NSString stringWithFormat:@"當(dāng)前緯度:%f",locationCoordinate.latitude];
//停止生成位置更新
[manager stopUpdatingLocation];
}
///通知代理位置管理器接收到更新的航向信息
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
CGAffineTransform transform =CGAffineTransformMakeRotation((newHeading.magneticHeading) * M_PI / 180.f );
self.headingRelatedImageView.transform = transform;
}
///當(dāng)此應(yīng)用程序的授權(quán)狀態(tài)更改時(shí)調(diào)用
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status API_AVAILABLE(ios(4.2), macos(10.7)){
NSLog(@"當(dāng)此應(yīng)用程序的授權(quán)狀態(tài)更改時(shí)調(diào)用");
switch (status) {
//用戶授權(quán)應(yīng)用程序隨時(shí)啟動(dòng)定位服務(wù)的權(quán)限
//用戶已授權(quán)僅在使用應(yīng)用程序時(shí)有訪問位置的權(quán)限
case kCLAuthorizationStatusAuthorizedAlways:
case kCLAuthorizationStatusAuthorizedWhenInUse:
//啟用定位
[self enablePositioning];
break;
default:
break;
}
}
///詢問代理是否應(yīng)顯示航向校準(zhǔn)警報(bào)
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager{
return YES;
}
///通知代理位置管理器無法檢索位置值
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error{
NSLog(@"發(fā)生異常了");
if(error.code == kCLErrorLocationUnknown) {
NSLog(@"無法檢索位置");
}
else if(error.code == kCLErrorNetwork) {
NSLog(@"網(wǎng)絡(luò)問題");
}
else if(error.code == kCLErrorDenied) {
NSLog(@"定位權(quán)限的問題");
}
}
///通知代理用戶已進(jìn)入指定區(qū)域
- (void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLRegion *)region API_AVAILABLE(ios(4.0), macos(10.8)) API_UNAVAILABLE(watchos, tvOS){
//異步檢索區(qū)域的狀態(tài)
[self.locationManager requestStateForRegion:region];
NSLog(@"以進(jìn)入指定區(qū)域");
self.regionMonitorLabel.text = @"以進(jìn)入指定區(qū)域";
}
///通知代理用戶已離開指定區(qū)域
- (void)locationManager:(CLLocationManager *)manager
didExitRegion:(CLRegion *)region API_AVAILABLE(ios(4.0), macos(10.8)) API_UNAVAILABLE(watchos, tvOS){
//異步檢索區(qū)域的狀態(tài)
[self.locationManager requestStateForRegion:region];
NSLog(@"以離開指定區(qū)域");
self.regionMonitorLabel.text = @"以離開指定區(qū)域";
}
///通知代理指定區(qū)域的狀態(tài)
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{
if (state == CLRegionStateInside) {
NSLog(@"以進(jìn)入指定區(qū)域");
self.regionMonitorLabel.text = @"以進(jìn)入指定區(qū)域";
} else if (state == CLRegionStateOutside) {
NSLog(@"以離開指定區(qū)域");
self.regionMonitorLabel.text = @"以離開指定區(qū)域";
} else {
NSLog(@"未知狀態(tài)");
self.regionMonitorLabel.text = @"未知狀態(tài)";
}
}
///通知代理發(fā)生區(qū)域監(jiān)視錯(cuò)誤
- (void)locationManager:(CLLocationManager *)manager
monitoringDidFailForRegion:(nullable CLRegion *)region
withError:(NSError *)error API_AVAILABLE(ios(4.0), macos(10.8)) API_UNAVAILABLE(watchos, tvOS){
//停止區(qū)域監(jiān)視
[self.locationManager stopMonitoringForRegion:region];
//CLCircularRegion類定義圓形地理區(qū)域的位置和邊界
CLCircularRegion *circularRegion = (CLCircularRegion *)region;
CLLocation *location = [[CLLocation alloc]initWithLatitude:circularRegion.center.latitude longitude:circularRegion.center.longitude];
//初始化地理編碼器對(duì)象
CLGeocoder *geocoder = [[CLGeocoder alloc]init];
//提交指定位置的反向地理編碼請(qǐng)求
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
if (placemarks.count >0) {
CLPlacemark *placeMark = placemarks[0];
NSLog(@"當(dāng)前國家 - %@",placeMark.country);//當(dāng)前國家
NSLog(@"當(dāng)前城市 - %@",placeMark.locality);//當(dāng)前城市
NSLog(@"當(dāng)前位置 - %@",placeMark.subLocality);//當(dāng)前位置
NSLog(@"當(dāng)前街道 - %@",placeMark.thoroughfare);//當(dāng)前街道
NSLog(@"具體地址 - %@",placeMark.name);//具體地址
NSString *errorGeocoder = [NSString stringWithFormat:@"%@%@%@,%@",IS_NOT_EMPTY(placeMark.locality)? placeMark.locality : @"",IS_NOT_EMPTY(placeMark.subLocality)? placeMark.subLocality : @"" ,IS_NOT_EMPTY(placeMark.thoroughfare)? placeMark.thoroughfare : @"",IS_NOT_EMPTY(placeMark.name)? placeMark.name : @""];
NSLog(@"%@區(qū)域監(jiān)聽發(fā)生錯(cuò)誤",errorGeocoder);
}else if(error == nil && placemarks.count){
NSLog(@"無位置和錯(cuò)誤返回");
}else if(error){
NSLog(@"loction error:%@",error);
}
}];
//輸出包含錯(cuò)誤的本地化描述的字符串
NSLog(@"區(qū)域監(jiān)控失敗 %@ %@",region, error.localizedDescription);
self.regionMonitorLabel.text = error.localizedDescription;
for (CLRegion *monitoredRegion in manager.monitoredRegions) {
NSLog(@"monitoredRegion: %@", monitoredRegion);
}
if ((error.domain != kCLErrorDomain || error.code != 5) &&
[manager.monitoredRegions containsObject:region]) {
NSString *message = [NSString stringWithFormat:@"%@ %@",
region, error.localizedDescription];
NSLog(@"%@",message);
}
}
///通知代理正在監(jiān)視新區(qū)域
- (void)locationManager:(CLLocationManager *)manager
didStartMonitoringForRegion:(CLRegion *)region API_AVAILABLE(ios(5.0), macos(10.8)) API_UNAVAILABLE(watchos, tvOS){
//CLCircularRegion類定義圓形地理區(qū)域的位置和邊界
CLCircularRegion *circularRegion = (CLCircularRegion *)region;
CLLocation *location = [[CLLocation alloc]initWithLatitude:circularRegion.center.latitude longitude:circularRegion.center.longitude];
//初始化地理編碼器對(duì)象
CLGeocoder *geocoder = [[CLGeocoder alloc]init];
//提交指定位置的反向地理編碼請(qǐng)求
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
if (placemarks.count >0) {
CLPlacemark *placeMark = placemarks[0];
NSLog(@"當(dāng)前國家 - %@",placeMark.country);//當(dāng)前國家
NSLog(@"當(dāng)前城市 - %@",placeMark.locality);//當(dāng)前城市
NSLog(@"當(dāng)前位置 - %@",placeMark.subLocality);//當(dāng)前位置
NSLog(@"當(dāng)前街道 - %@",placeMark.thoroughfare);//當(dāng)前街道
NSLog(@"具體地址 - %@",placeMark.name);//具體地址
NSString *errorGeocoder = [NSString stringWithFormat:@"%@%@%@,%@",IS_NOT_EMPTY(placeMark.locality)? placeMark.locality : @"",IS_NOT_EMPTY(placeMark.subLocality)? placeMark.subLocality : @"" ,IS_NOT_EMPTY(placeMark.thoroughfare)? placeMark.thoroughfare : @"",IS_NOT_EMPTY(placeMark.name)? placeMark.name : @""];
self.monitoringLabel.text = [NSString stringWithFormat:@"在監(jiān)視新區(qū)域:%@",errorGeocoder];
}else if(error == nil && placemarks.count){
NSLog(@"無位置和錯(cuò)誤返回");
}else if(error){
NSLog(@"loction error:%@",error);
}
}];
}
///通知代理位置更新已暫停
- (void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager API_AVAILABLE(ios(6.0)) API_UNAVAILABLE(watchos, tvos, macOS){
self.locationUpdateLabel.text = @"位置更新已暫停";
}
///通知代理位置更新的傳遞已恢復(fù)
- (void)locationManagerDidResumeLocationUpdates:(CLLocationManager *)manager API_AVAILABLE(ios(6.0)) API_UNAVAILABLE(watchos, tvos, macOS){
self.locationUpdateLabel.text = @"位置更新的傳遞已恢復(fù)";
}
///通知代理不再延遲更新
- (void)locationManager:(CLLocationManager *)manager
didFinishDeferredUpdatesWithError:(nullable NSError *)error API_AVAILABLE(ios(6.0), macos(10.9)) API_UNAVAILABLE(watchos, tvOS){
self.locationUpdateLabel.text = @"不再延遲更新";
}
///通知代理一個(gè)或多個(gè)信標(biāo)在范圍內(nèi)韵丑。
- (void)locationManager:(CLLocationManager *)manager
didRangeBeacons:(NSArray<CLBeacon *> *)beacons
inRegion:(CLBeaconRegion *)region{
}
///通知代理檢測(cè)到滿足約束的信標(biāo)。
- (void)locationManager:(CLLocationManager *)manager
didRangeBeacons:(NSArray<CLBeacon *> *)beacons
satisfyingConstraint:(CLBeaconIdentityConstraint *)beaconConstraint API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(watchos, tvos, macOS){
}
///通知代理未檢測(cè)到滿足約束的信標(biāo)虚缎。
- (void)locationManager:(CLLocationManager *)manager
didFailRangingBeaconsForConstraint:(CLBeaconIdentityConstraint *)beaconConstraint
error:(NSError *)error API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(watchos, tvos, macOS){
}
///通知代理收到了新的與訪問相關(guān)的事件
- (void)locationManager:(CLLocationManager *)manager didVisit:(CLVisit *)visit API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(watchos, tvos, macOS){
}
@end
樣式如圖 :