導入CoreLocation框架以及對應的主頭文件ios
#import <CoreLocation/CoreLocation.h>
建立CLLocationManager對象並設置代理git
self.locationM = [[CLLocationManager alloc] init]; self.locationM.delegate = self;
調用方法,開始更新用戶位置信息github
[self.locationM startUpdatingLocation];
在對應的代理方法中獲取位置信息api
-(void)locationManager:(nonnull CLLocationManager *)manager didUpdateLocations:(nonnull NSArray<CLLocation > *)locations { NSLog(@"每當請求到位置信息時, 都會調用此方法"); }
每隔多少米定位一次app
代碼: self.locationM.distanceFilter = 100; 功能: 只有當最新的位置與上一次獲取的位置之間的距離, 大於這個值時, 纔會經過代理告訴外界
設置定位精確度框架
代 碼: self.locationM.desiredAccuracy = kCLLocationAccuracyBest; 功 能: 經過設置此屬性, 獲取不一樣精確度的位置信息 注意事項: 精確度越高,越耗電,定位所需時間越長 枚舉註解:
枚舉值 | 含義 |
---|---|
kCLLocationAccuracyBestForNavigation | 最適合導航 |
kCLLocationAccuracyBest | 精度最好的 |
kCLLocationAccuracyNearestTenMeters | 附近10米 |
kCLLocationAccuracyHundredMeters | 附近100米 |
kCLLocationAccuracyKilometer | 附近1000米 |
kCLLocationAccuracyThreeKilometers | 附近3000米 |
1. 定位常識 1) 標準定位服務(基於gps/基站/wifi定位, 具體使用哪一種,蘋果有本身規則) > 程序關閉,就無法獲取位置 2) 顯著的位置變化定位服務(使用基站進行定位,因此必需要求設備有電話模塊) > 當app被徹底關閉時,也能夠接收到位置通知,並讓app進入到後臺處理 > 定位精度相比於上面,精度不大,因此耗電小,並且定位更新頻率依據基站密度而定 2. 應用場景 1) 若是要求定位及時,精度較高,而且運行時間較短,可以使用標準定位; 2) 若是長時間監控用戶位置,用戶移動速度比較快(例如打車軟件),可以使用後者
1. XCode7.0以前版本,例如XCode6.4版本 2. 模擬器選擇iOS8.0以前的版本 * 緣由 : XCode7.0(包含7.0)以後不支持iOS8.0以前的模擬器
1. 定位不到, 對應的代理方法不執行 首先,檢查運行的模擬器是不是iOS8.0以前的系統版本 其次,檢查模擬器是否設置位置數據 第三,確保代碼無問題(通常都是代理沒有設置,或者位置管理器對象是局部變量,亦或是位置管理器對象沒有被強引用) 第四,絕逼是模擬器BUG, 請重置模擬器(是重置,不是重啓)
導入CoreLocation框架以及對應的主頭文件ide
#import <CoreLocation/CoreLocation.h>
建立CLLocationManager對象並設置代理測試
self.locationM = [[CLLocationManager alloc] init]; self.locationM.delegate = self;
請求前臺定位受權, 並在Info.Plist文件中配置Key ( Nslocationwheninuseusagedescription )動畫
[self.locationM requestWhenInUseAuthorization];
調用方法,開始更新用戶位置信息ui
[self.locationM startUpdatingLocation];
在對應的代理方法中獲取位置信息
-(void)locationManager:(nonnull CLLocationManager *)manager didUpdateLocations:(nonnull NSArray<CLLocation > *)locations { NSLog(@"每當請求到位置信息時, 都會調用此方法"); }
請求先後臺定位受權,並在info.plist文件中配置KEY ( NSLocationAlwaysUsageDescription )
[self.locationM requestAlwaysAuthorization];
注意:不須要勾選後臺模式, 也能夠進行後臺定位
注意:此時受權狀態若是是先後臺定位, 那麼即便APP退到後臺時, 屏幕頂部會也不會出現藍條
實現如下代理方法便可
// 當用戶受權狀態發生變化時調用 -(void)locationManager:(nonnull CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { switch (status) { // 用戶還未決定 case kCLAuthorizationStatusNotDetermined: { NSLog(@"用戶還未決定"); break; } // 訪問受限(蘋果預留選項,暫時沒用) case kCLAuthorizationStatusRestricted: { NSLog(@"訪問受限"); break; } // 定位關閉時和對此APP受權爲never時調用 case kCLAuthorizationStatusDenied: { // 定位是否可用(是否支持定位或者定位是否開啓) if([CLLocationManager locationServicesEnabled]) { NSLog(@"定位開啓,但被拒"); // 在此處, 應該提醒用戶給此應用受權, 並跳轉到"設置"界面讓用戶進行受權 // 在iOS8.0以後跳轉到"設置"界面代碼 NSURL *settingURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; if([[UIApplication sharedApplication] canOpenURL:settingURL]) { [[UIApplication sharedApplication] openURL:settingURL]; } }else { NSLog(@"定位關閉,不可用"); } break; } // 獲取先後臺定位受權 case kCLAuthorizationStatusAuthorizedAlways: // case kCLAuthorizationStatusAuthorized: // 失效,不建議使用 { NSLog(@"獲取先後臺定位受權"); break; } // 得到前臺定位受權 case kCLAuthorizationStatusAuthorizedWhenInUse: { NSLog(@"得到前臺定位受權"); break; } default: break; } }
1. XCode版本無要求 2. 模擬器選擇iOS8.0以後的版本
1. 定位不到, 對應的代理方法不執行 首先,檢查是否請求受權, 並設置了對應的KEY 其次,檢查模擬器是否設置位置數據 第三,確保代碼無問題(通常都是代理沒有設置,或者位置管理器對象是局部變量,亦或是位置管理器對象沒有被強引用) 第四,絕逼是模擬器BUG, 請重置模擬器(是重置,不是重啓)
(同iOS8.0以後一致, 無任何變化, 都須要主動請求受權)
在前臺定位基礎上, 勾選後臺模式Location updates, 而且設置如下屬性爲YES
if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) { self.locationM.allowsBackgroundLocationUpdates = YES; }
請求先後臺定位受權,並在info.plist文件中配置KEY ( NSLocationAlwaysUsageDescription )
[self.locationM requestAlwaysAuthorization];
單次定位請求;
代 碼: [self.locationM requestLocation]; 功 能: 獲取一次位置信息 實現邏輯: (1) 按照定位精確度從低到高進行排序,逐個進行定位.若是在有效時間內, 定位到了精確度最好的位置, 那麼就把對應的位置經過代理告知外界. (2) 若是獲取到的位置不是精確度最高的那個,也會在定位超時後,經過代理告訴外界. 注意事項: (1) 必須實現代理的-locationManager:didFailWithError:方法 (2) 不能與startUpdatingLocation方法同時使用
1. XCode版本要求7.0版本以上 2. 模擬器選擇iOS9.0以後的版本
1. 單次定位在模擬器上測試不出效果? 答: 由於模擬器的位置是固定的, 因此沒法測試出效果, 請使用真機進行測試.
> coordinate : 當前位置所在的經緯度數據 > altitude : 海拔 > speed : 當前速度 > course : 航向(設備移動的方向, 值域範圍:0.0 ~ 359.9, 正北方向爲0.0)
代碼: - (CLLocationDistance)distanceFromLocation:(CLLocation *)location 做用: 計算兩個位置對象之間的物理距離, 單位是(米)
1. 場景演示:打印當前用戶的行走方向,偏離角度以及對應的行走距離, 例如:」北偏東30度方向,移動了8米」 2. 實現步驟: 1> 獲取對應的方向偏向(例如」正東」,」東偏南」) 2> 獲取對應的偏離角度(並判斷是不是正方向) 3> 計算行走距離 4> 打印信息
使用位置前, 務必判斷當前獲取的位置是否有效
代碼: if (location.horizontalAccuracy < 0) return; 功能: 若是水平精確度小於零, 表明雖然能夠獲取位置對象, 可是數據錯誤, 不可用
1) 導航 2) 電商APP,獲取用戶所在城市(須要與(反)地理編碼聯合使用) 3) 數據採集用戶信息(例如,統計app使用分佈) 4) 查找周邊(周邊好友, 周邊商家等等)
** 因爲定位很是耗電; 因此爲了給用戶省電, 你能夠遵照如下小經驗 **
1)不須要獲取用戶位置時,必定要關閉定位服務: 2)若是能知足項目需求,儘量的使用」監聽顯著位置變化」的定位服務(打車app) 3)若是能夠,儘量使用低精度的desiredAccuracy 4)若是是數據採集,(通常都是週期性的去輪詢用戶位置),在輪詢期間必定要關閉定位
獲取設備朝向
1) 導入CoreLocation框架以及對應的主頭文件 #import <CoreLocation/CoreLocation.h> 2) 建立CLLocationManager對象並設置代理 self.locationM = [[CLLocationManager alloc] init]; self.locationM.delegate = self; 3) 調用方法, 開始獲取設備朝向 [self.locationM startUpdatingHeading]; 4) 在對應的代理方法中獲取設備朝向信息 -(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading { // 旋轉圖片代碼 }
旋轉圖片
// 1.判斷當前的角度是否有效(若是此值小於0,表明角度無效) if(newHeading.headingAccuracy < 0) return; // 2.獲取當前設備朝向(磁北方向) CGFloat angle = newHeading.magneticHeading; // 3.轉換成爲弧度 CGFloat radian = angle / 180.0 * M_PI; // 4.帶動畫反向旋轉指南針 [UIView animateWithDuration:0.5 animations:^{ self.compassView.transform = CGAffineTransformMakeRotation(-radian); }];
磁北角度: newHeading.magneticHeading ------- 相對於"磁北方向"產生的角度 真北角度: newHeading.trueHeading ------- 相對於"真北方向"產生的角度
1. 獲取設備朝向前, 先判斷"磁力計"是否可用 [CLLocationManager headingAvailable]; 2. 獲取朝向前, 判斷當前朝向信息是否有效 if(newHeading.headingAccuracy < 0) return; 3. 注意與"航向"的區別 設備朝向是指手機的朝向; "航向"能夠理解爲設備的移動方向 4. 使用"磁力計"傳感器獲取設備朝向, 不須要請求用戶受權 由於設備朝向不涉及用戶隱私
1. XCode版本無要求(建議:XCode7.0不須要開發者帳號也能夠進行真機調試) 2. 必需要求真機設備(只有真機設備纔有"磁力計"傳感器)
區 域 : 就是指劃定的一塊地域範圍(好比圓形區域, 則由區域中心, 和半徑組成) 區域監聽 : 是指,咱們經過代碼指定一個區域, 而後當用戶持握設備進入或者離開指定區域, 咱們都能監聽到.
導入CoreLocation框架以及對應的主頭文件
#import <CoreLocation/CoreLocation.h>
建立CLLocationManager對象並設置代理
self.locationM = [[CLLocationManager alloc] init]; self.locationM.delegate = self;
請求先後臺定位, 或前臺定位受權, 並在Info.Plist文件中配置相應的Key
[self.locationM requestAlwaysAuthorization]; // [self.locationM requestWhenInUseAuthorization];
建立一個區域, 並開始監聽
// 1. 判斷區域監聽服務是否可用(定位服務是否關閉, 定位是否受權, 是否開啓飛行模式) if ([CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]]) { // 建立區域中心 CLLocationCoordinate2D center = CLLocationCoordinate2DMake(29.12345, 131.23456); // 建立區域(指定區域中心,和區域半徑) CLLocationDistance radius = 1000; // 判斷區域半徑是否大於最大監聽區域半徑,若是大於, 就無法監聽 if (radius > self.locationM.maximumRegionMonitoringDistance) { radius = self.locationM.maximumRegionMonitoringDistance; } CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:radius identifier:@"江哥"]; // 開始監聽指定區域(只有用戶有進入區域, 或者離開區域動做的時候 纔會經過代理告訴外界) // 例:當一開始在區域內,不會通知代理,只有進入或離開區域時纔會調用 [self.locationM startMonitoringForRegion:region]; // 請求某個區域的狀態 // 不止能夠獲取到指定區域的狀態, 並且當狀態發生變化時, 也會調用對應的代理方法, 告訴咱們 [self.locationM requestStateForRegion:region]; } else { NSLog(@"區域監聽不可用"); }
在對應的代理方法中監聽區域狀態
// 進去監聽區域後調用(調用一次) -(void)locationManager:(nonnull CLLocationManager *)manager didEnterRegion:(nonnull CLRegion *)region { NSLog(@"進入區域---%@", region.identifier); [manager stopMonitoringForRegion:region]; } // 離開監聽區域後調用(調用一次) -(void)locationManager:(nonnull CLLocationManager *)manager didExitRegion:(nonnull CLRegion *)region { NSLog(@"離開區域---%@", region.identifier); } /** * 當前請求指定區域狀態時, 回調的代理方法 * @param manager 位置管理者 * @param state 狀態 * @param region 區域 */ -(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region { /** * CLRegionStateUnknown, // 不知道 CLRegionStateInside, // 在區域內部 CLRegionStateOutside // 在區域外部 */ if(state == CLRegionStateInside) { self.noticeLabel.text = @"江哥歡迎你, 給你技術"; }else if (state == CLRegionStateOutside) { self.noticeLabel.text = @"歡迎下次再來"; } }
監聽某個區域時, 只有進入或者離開這個區域時, 才能回調對應的方法, 是一個進入或者離開的動做
若是想知道某一個區域的當前狀態(識別用戶是在區域內部, 仍是區域外部), 則須要使用如下方法
代 碼: [self.locationM requestStateForRegion:region]; 回調代理: // 請求某個區域狀態時, 回調的代理方法 -(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region { switch (state) { case CLRegionStateUnknown: NSLog(@"未知狀態"); break; case CLRegionStateInside: NSLog(@"在區域內部"); break; case CLRegionStateOutside: NSLog(@"在區域外部"); break; default: break; } }
XCode版本無要求 iOS模擬器版本無要求
1. 想要作區域監聽, 在iOS8.0以後, 必須請求位置受權 代碼: [self.locationM requestAlwaysAuthorization]; 緣由: 區域監聽的原理就是獲取用戶的位置, 而後在判斷該位置是否在制定區域內, 因此會涉及到用戶隱私(位置), 而在iOS8.0以後, 想要訪問用戶位置信息, 就須要主動請求受權; 2. 使用前, 先判斷區域監聽是否可用 代碼: [CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]] 3. 注意區域半徑是否大於最大區域監聽半徑(若是大於, 則沒法監聽成功) 代碼: radius > self.locationM.maximumRegionMonitoringDistance
1. 區域監聽, 測試沒有效果? 首先, 肯定代碼沒有問題, 是否有請求受權; 其次, 嘗試修改模擬器位置信息, 觸發進入區域或離開區域的動做 第三, 若是模擬器出現BUG, 定位不到, 也會沒法斷定當前區域狀態; 因此, 最後能夠嘗試重置模擬器.
地理編碼: 是指根據地址關鍵字, 將其轉換成爲對應的經緯度等信息; 發地理編碼: 是指根據經緯度信息, 將其轉換成爲對應的省市區街道等信息;
導入CoreLocation框架以及對應的主頭文件
#import <CoreLocation/CoreLocation.h>
建立CLGeocoder對象
self.geoC = [[CLGeocoder alloc] init];
根據地址關鍵字, 進行地理編碼
// 直接根據地址進行地理編碼(返回結果可能有多個,由於一個地點有重名) [self.geoC geocodeAddressString:@"上海" completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) { // 包含區,街道等信息的地標對象 CLPlacemark *placemark = [placemarks firstObject]; // 城市名稱 NSString *city = placemark.locality; // 街道名稱 NSString *street = placemark.thoroughfare; // 全稱 NSString *name = placemark.name; }];
導入CoreLocation框架以及對應的主頭文件
#import <CoreLocation/CoreLocation.h>
建立CLGeocoder對象
self.geoC = [[CLGeocoder alloc] init];
根據經緯度信息, 進行反地理編碼
// 根據經緯度信息進行反地理編碼 [self.geoC reverseGeocodeLocation:[[CLLocation alloc] initWithLatitude:21.123 longitude:123.345] completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) { // 包含區,街道等信息的地標對象 CLPlacemark *placemark = [placemarks firstObject]; // 城市名稱 NSString *city = placemark.locality; // 街道名稱 NSString *street = placemark.thoroughfare; // 全稱 NSString *name = placemark.name; }];
location : CLLocation 類型, 位置對象信息, 裏面包含經緯度, 海拔等等 region : CLRegion 類型, 地標對象對應的區域 addressDictionary : NSDictionary 類型, 存放街道,省市等信息 name : NSString 類型, 地址全稱 thoroughfare : NSString 類型, 街道名稱 locality : NSString 類型, 城市名稱 administrativeArea : NSString 類型, 省名稱 country : NSString 類型, 國家名稱
* 必須聯網 XCode版本不限 iOS模擬器系統版本不限
1. 測試無數據? 首先, 檢查是否有聯網; 其次, 若是是反地理編碼,可嘗試更換經緯度再次嘗試, 有的經緯度沒有對應信息
1. 通常與定位結合使用, 肯定當前位置的具體地理信息
由於使用CoreLocation框架進行獲取用戶位置信息, 是經過代理進行回調; 而第三方框架將"代理模擬"轉換成爲"block模式"; 使用起來比較方便, 並且額外增長了超時時間等功能.
名稱: locationManager 地址: [link](https://github.com/intuit/LocationManager)
參照該框架對應的 readME
通常集成第三方框架到項目中, 請先確保該框架沒有問題, 而後再向項目中集成
代理模式到block模式的轉換
主要思想就是,先記錄下外界傳遞過來的block, 而後在對應的代理方法裏面執行這個block;