iOS核心筆記——CoreLocation框架


一. iOS8.0之前的定位:

1. 前台定位:

  1. 導入CoreLocation框架以及對應的主頭文件:

    1 #import <CoreLocation/CoreLocation.h>
     
  2. 創建CLLocationManager對象並設置代理:

    1 self.locationM = [[CLLocationManager alloc] init];
    2 self.locationM.delegate = self;

     

  3. 調用方法,開始更新用戶位置信息:

    1 [self.locationM startUpdatingLocation];

     

  4. 在對應的代理方法中獲取位置信息:

    1 -(void)locationManager:(nonnull CLLocationManager *)manager didUpdateLocations:(nonnull NSArray<CLLocation > *)locations  
    2  {
    3      NSLog(@"每當請求到位置信息時, 都會調用此方法");  
    4  }

     


 

 

2. 后台定位:

  1. 在前台定位基礎上, 勾選后台模式Location updates

 

 

3. 額外設置:

  1. 每隔多少米定位一次:

    代碼:
    self.locationM.distanceFilter = 100;
    功能:
    只有當最新的位置與上一次獲取的位置之間的距離, 大於這個值時, 才會通過代理告訴外界
     
  2. 設置定位精確度:

     代 碼: self.locationM.desiredAccuracy = kCLLocationAccuracyBest; 功 能: 通過設置此屬性, 獲取不同精確度的位置信息 注意事項: 精確度越高,越耗電,定位所需時間越長 枚舉注解:  
    
    
    枚舉值 含義
    kCLLocationAccuracyBestForNavigation 最適合導航
    kCLLocationAccuracyBest 精度最好的
    kCLLocationAccuracyNearestTenMeters 附近10米
    kCLLocationAccuracyHundredMeters 附近100米
    kCLLocationAccuracyKilometer 附近1000米
    kCLLocationAccuracyThreeKilometers 附近3000米

 

 

4. 知識補充:

1. 定位常識: 1) 標准定位服務(基於gps/基站/wifi定位, 具體使用哪種,蘋果有自己規則) > 程序關閉,就沒法獲取位置 
2) 顯著的位置變化定位服務(使用基站進行定位,所以必須要求設備有電話模塊) > 當app被完全關閉時,也可以接收到位置通知,並讓app進入到后台處理 > 定位精度相比於上面,精度不大,所以耗電小,而且定位更新頻率依據基站密度而定


2. 應用場景: 1) 如果要求定位及時,精度較高,並且運行時間較短,可使用標准定位; 2) 如果長時間監控用戶位置,用戶移動速度比較快(例如打車軟件),可使用后者


5. 測試環境:

1. XCode7.0之前版本,例如XCode6.4版本;
2. 模擬器選擇iOS8.0之前的版本 * 原因 : XCode7.0(包含7.0)之后不支持iOS8.0之前的模擬器


 
        

6. 常見問題總結:

1. 定位不到, 對應的代理方法不執行:
①、首先,檢查運行的模擬器是否是iOS8.0之前的系統版本; ②、其次,檢查模擬器是否設置位置數據; ③、第三,確保代碼無問題(一般都是代理沒有設置,或者位置管理器對象是局部變量,亦或是位置管理器對象沒有被強引用); ④、第四,絕逼是模擬器BUG, 請重置模擬器(是重置,不是重啟)。

二. iOS8.0之后定位:

1. 前台定位:

  1. 導入CoreLocation框架以及對應的主頭文件

    1 #import <CoreLocation/CoreLocation.h>

     

  2. 創建CLLocationManager對象並設置代理:

    1 self.locationM = [[CLLocationManager alloc] init];
    2 self.locationM.delegate = self;

     

  3. 請求前台定位授權, 並在Info.Plist文件中配置Key ( NSLocationWhenInUseusagedescription ):

    1 [self.locationM requestWhenInUseAuthorization];

     

  4. 調用方法,開始更新用戶位置信息:

    1 [self.locationM startUpdatingLocation];

     

  5. 在對應的代理方法中獲取位置信息:

    1  -(void)locationManager:(nonnull CLLocationManager *)manager didUpdateLocations:(nonnull NSArray<CLLocation > *)locations  
    2  {
    3      NSLog(@"每當請求到位置信息時, 都會調用此方法");  
    4  }

     


 

 

2. 后台定位:

方案一:
  1. 在前台定位基礎上, 勾選后台模式Location updates。
       注意: 此時授權狀態如果是前台定位, 那么當APP退到后台時, 屏幕頂部會出現藍條。
方案二:
  1. 請求前后台定位授權,並在info.plist文件中配置KEY ( NSLocationAlwaysUsageDescription )

    1 [self.locationM requestAlwaysAuthorization];

     

    注意: 不需要勾選后台模式, 也可以進行后台定位;

    注意: 此時授權狀態如果是前后台定位, 那么即使APP退到后台時, 屏幕頂部會也不會出現藍條。


 

 

3. 監聽用戶授權狀態:

  1. 實現以下代理方法即可:

     1 // 當用戶授權狀態發生變化時調用
     2  -(void)locationManager:(nonnull CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
     3  {
     4      switch (status) {
     5          // 用戶還未決定
     6          case kCLAuthorizationStatusNotDetermined:
     7          {
     8                  NSLog(@"用戶還未決定");
     9                  break;
    10              }
    11          // 訪問受限(蘋果預留選項,暫時沒用)
    12          case kCLAuthorizationStatusRestricted:
    13          {
    14                  NSLog(@"訪問受限");
    15                  break;
    16          }
    17          // 定位關閉時和對此APP授權為never時調用
    18          case kCLAuthorizationStatusDenied:
    19          {
    20                  // 定位是否可用(是否支持定位或者定位是否開啟)
    21                  if([CLLocationManager locationServicesEnabled])
    22                  {
    23                      NSLog(@"定位開啟,但被拒");
    24                      // 在此處, 應該提醒用戶給此應用授權, 並跳轉到"設置"界面讓用戶進行授權
    25                      // 在iOS8.0之后跳轉到"設置"界面代碼
    26                      NSURL *settingURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
    27                      if([[UIApplication sharedApplication] canOpenURL:settingURL])
    28                      {
    29                          [[UIApplication sharedApplication] openURL:settingURL];
    30                      }    
    31                  }else
    32                  {
    33                      NSLog(@"定位關閉,不可用");
    34                  }
    35                  break;
    36          }
    37          // 獲取前后台定位授權
    38          case kCLAuthorizationStatusAuthorizedAlways:
    39          //  case kCLAuthorizationStatusAuthorized: // 失效,不建議使用
    40          {
    41              NSLog(@"獲取前后台定位授權");
    42              break;
    43          }
    44          // 獲得前台定位授權
    45          case kCLAuthorizationStatusAuthorizedWhenInUse:
    46          {
    47              NSLog(@"獲得前台定位授權");
    48              break;
    49          }
    50          default:
    51          break;
    52      }
    53  }                                    

     


 

 

4. 測試環境:

1. XCode版本無要求;
2. 模擬器選擇iOS8.0之后的版本。


 
        

5. 常見問題總結:

1. 定位不到, 對應的代理方法不執行: ①、首先,檢查是否請求授權, 並設置了對應的KEY; ②、其次,檢查模擬器是否設置位置數據; ③、確保代碼無問題(一般都是代理沒有設置,或者位置管理器對象是局部變量,亦或是位置管理器對象沒有被強引用); ④、絕逼是模擬器BUG, 請重置模擬器(是重置,不是重啟)。 

三. iOS9.0 定位補充:

1. 定位變化:

1-1、前台定位:

 同iOS8.0之后一致, 無任何變化, 都需要主動請求授權。

     


 

 

1-2、 后台定位:

方案一:
  1. 在前台定位基礎上, 勾選后台模式Location updates, 並且設置以下屬性為YES:

    1 if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0)
    2   {
    3       self.locationM.allowsBackgroundLocationUpdates = YES;
    4   }

     

方案二:
  1. 請求前后台定位授權,並在info.plist文件中配置KEY ( NSLocationAlwaysUsageDescription )

    1 [self.locationM requestAlwaysAuthorization];

     


 

 

2. 新的API:

  1. 單次定位請求;

     代 碼: [self.locationM requestAlwaysAuthorization]; 功 能: 獲取一次位置信息 實現邏輯: (1) 按照定位精確度從低到高進行排序,逐個進行定位.如果在有效時間內, 定位到了精確度最好的位置, 那么就把對應的位置通過代理告知外界. (2) 如果獲取到的位置不是精確度最高的那個,也會在定位超時后,通過代理告訴外界. 注意事項: (1) 必須實現代理的-locationManager:didFailWithError:方法 (2) 不能與startUpdatingLocation方法同時使用 
    

 

 

3. 測試環境:

1. XCode版本要求7.0版本以上; 2. 模擬器選擇iOS9.0之后的版本。 
 

 
        

4. 常見問題總結:

1. 單次定位在模擬器上測試不出效果? 答: 因為模擬器的位置是固定的, 所以無法測試出效果, 請使用真機進行測試. 

四. CLLocation對象詳解:

1. 屬性解釋:

coordinate
當前位置所在的經緯度數據
altitude
海拔
speed
當前速度
course
航向(設備移動的方向, 值域范圍:0.0 ~ 259.9, 正北方向為0.0)

 



2. 重要方法:

1  - (CLLocationDistance)distanceFromLocation:(CLLocation *)location

作用: 計算兩個位置對象之間的物理距離, 單位是(米)
 

 
        

3. 場景演練:

1. 場景演示:打印當前用戶的行走方向,偏離角度以及對應的行走距離, 例如:”北偏東30度方向,移動了8米”。
2. 實現步驟: 1> 獲取對應的方向偏向(例如”正東”,”東偏南”); 2> 獲取對應的偏離角度(並判斷是否是正方向); 3> 計算行走距離; 4> 打印信息。
 
        

4. 注意事項:

  1. 使用位置前, 務必判斷當前獲取的位置是否有效:

    1 if (location.horizontalAccuracy < 0) return;

    功能: 如果水平精確度小於零, 代表雖然可以獲取位置對象, 但是數據錯誤, 不可用
     

* 經驗小結:

一. 定位的應用場景:

 1) 導航; 2) 電商APP,獲取用戶所在城市(需要與(反)地理編碼聯合使用); 3) 數據采集用戶信息(例如,統計app使用分布); 4) 查找周邊(周邊好友, 周邊商家等等)。 
 
        
 
        

二. 開發經驗:

由於定位非常耗電; 所以為了給用戶省電, 你可以遵守以下小經驗:

 1)不需要獲取用戶位置時,一定要關閉定位服務; 2)如果能滿足項目需求,盡可能的使用”監聽顯著位置變化”的定位服務(打車app); 3)如果可以,盡可能使用低精度的desiredAccuracy; 4)如果是數據采集,(一般都是周期性的去輪詢用戶位置),在輪詢期間一定要關閉定位。 

五. 指南針效果實現:

1. 實現思路:

  1. 利用"磁力計"傳感器,獲取設備朝向;
  2. 根據設備朝向反向旋轉"指南針"圖片。

 

2. 代碼實現:

  1. 獲取設備朝向:

     1 1) 導入CoreLocation框架以及對應的主頭文件
     2      #import <CoreLocation/CoreLocation.h>
     3 
     4  2) 創建CLLocationManager對象並設置代理
     5      self.locationM = [[CLLocationManager alloc] init];
     6      self.locationM.delegate = self;
     7 
     8  3) 調用方法, 開始獲取設備朝向
     9      [self.locationM startUpdatingHeading];
    10 
    11  4) 在對應的代理方法中獲取設備朝向信息
    12      -(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
    13      {
    14          // 旋轉圖片代碼
    15      }

     

  2. 旋轉圖片:

     1 // 1.判斷當前的角度是否有效(如果此值小於0,代表角度無效)
     2  if(newHeading.headingAccuracy < 0)
     3  return;
     4 
     5  // 2.獲取當前設備朝向(磁北方向)
     6  CGFloat angle = newHeading.magneticHeading;
     7 
     8  // 3.轉換成為弧度
     9  CGFloat radian = angle / 180.0 * M_PI;
    10 
    11  // 4.帶動畫反向旋轉指南針
    12  [UIView animateWithDuration:0.5 animations:^{
    13      self.compassView.transform = CGAffineTransformMakeRotation(-radian);
    14  }];

     


 

3. 概念補充:

 磁北角度: newHeading.magneticHeading ------- 相對於"磁北方向"產生的角度 真北角度: newHeading.trueHeading ------- 相對於"真北方向"產生的角度 

 
        

4. 注意事項:

 1 1. 獲取設備朝向前, 先判斷"磁力計"是否可用:
 2         [CLLocationManager headingAvailable];
 3 
 4 2. 獲取朝向前, 判斷當前朝向信息是否有效:
 5         if(newHeading.headingAccuracy < 0) return;
 6 
 7 3. 注意與"航向"的區別:
 8         設備朝向是指手機的朝向; "航向"可以理解為設備的移動方向
 9 
10 4. 使用"磁力計"傳感器獲取設備朝向, 不需要請求用戶授權;因為設備朝向不涉及用戶隱私。

 


 

5.測試環境

 1. XCode版本無要求(建議:XCode7.0不需要開發者賬號也可以進行真機調試); 2. 必須要求真機設備(只有真機設備才有"磁力計"傳感器)

六. 區域監聽:

1.概念解釋:

 區 域 : 就是指划定的一塊地域范圍(比如圓形區域, 則由區域中心, 和半徑組成) 區域監聽 : 是指,我們通過代碼指定一個區域, 然后當用戶持握設備進入或者離開指定區域, 我們都能監聽到. 
 
        
 
        

2. 監聽指定區域:

  1. 導入CoreLocation框架以及對應的主頭文件:

    1 #import <CoreLocation/CoreLocation.h>

     

  2. 創建CLLocationManager對象並設置代理:

    1 self.locationM = [[CLLocationManager alloc] init];
    2 self.locationM.delegate = self;

     

  3. 請求前后台定位, 或前台定位授權, 並在Info.Plist文件中配置相應的Key:

    [self.locationM requestAlwaysAuthorization];
    // [self.locationM requestWhenInUseAuthorization]; 

     

  4. 創建一個區域, 並開始監聽:

     1 // 1. 判斷區域監聽服務是否可用(定位服務是否關閉, 定位是否授權, 是否開啟飛行模式)
     2  if ([CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]]) 
     3  {
     4 
     5      // 創建區域中心
     6      CLLocationCoordinate2D center = CLLocationCoordinate2DMake(29.12345, 131.23456);
     7 
     8      // 創建區域(指定區域中心,和區域半徑)
     9      CLLocationDistance radius = 1000;
    10 
    11      // 判斷區域半徑是否大於最大監聽區域半徑,如果大於, 就沒法監聽
    12      if (radius > self.locationM.maximumRegionMonitoringDistance) {
    13          radius = self.locationM.maximumRegionMonitoringDistance;
    14      }
    15      CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:radius identifier:@"小碼哥"];
    16 
    17      // 開始監聽指定區域
    18      [self.locationM startMonitoringForRegion:region];
    19
    20 }else 21 { 22 NSLog(@"區域監聽不可用"); 23 }

     

  5. 在對應的代理方法中監聽區域狀態:

     1 // 進去監聽區域后調用(調用一次)
     2  -(void)locationManager:(nonnull CLLocationManager *)manager didEnterRegion:(nonnull CLRegion *)region
     3  {
     4      NSLog(@"進入區域---%@", region.identifier);
     5      [manager stopMonitoringForRegion:region];
     6  }
     7 
     8  // 離開監聽區域后調用(調用一次)
     9  -(void)locationManager:(nonnull CLLocationManager *)manager didExitRegion:(nonnull CLRegion *)region
    10  {
    11      NSLog(@"離開區域---%@", region.identifier);
    12  }

     


 

3. 獲取某個區域的當前狀態:

監聽某個區域時, 只有進入或者離開這個區域時, 才能回調對應的方法, 是一個進入或者離開的動作 如果想知道某一個區域的當前狀態(識別用戶是在區域內部, 還是區域外部), 則需要使用以下方法

代 碼:
1 [self.locationM requestStateForRegion:region];

回調代理:
 1 // 請求某個區域狀態時, 回調的代理方法
 2     -(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
 3 {
 4     switch (state) {
 5         case CLRegionStateUnknown:
 6             NSLog(@"未知狀態");
 7             break;
 8         case CLRegionStateInside:
 9             NSLog(@"在區域內部");
10             break;
11         case CLRegionStateOutside:
12             NSLog(@"在區域外部");
13             break;
14         default:
15          break;
16     }
17 }

 


 

4. 測試環境:

XCode版本無要求; iOS模擬器版本無要求。 
 
        
 
        

5. 注意事項:

1. 想要做區域監聽, 在iOS8.0之后, 必須請求位置授權:
1 代碼: [self.locationM requestAlwaysAuthorization];
2 
3 原因: 區域監聽的原理就是獲取用戶的位置, 然后在判斷該位置是否在制定區域內, 所以會涉及到用戶隱私(位置), 而在iOS8.0之后, 想要訪問用戶位置信息, 就需要主動請求授權;

2. 使用前, 先判斷區域監聽是否可用:
1 [CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]]
 
        
 3. 注意區域半徑是否大於最大區域監聽半徑(如果大於, 則無法監聽成功)
1 radius > self.locationM.maximumRegionMonitoringDistance
 
        
 
        
 
        

6. 常見問題:

1. 區域監聽, 測試沒有效果? 首先, 確定代碼沒有問題, 是否有請求授權; 其次, 嘗試修改模擬器位置信息, 觸發進入區域或離開區域的動作 第三, 如果模擬器出現BUG, 定位不到, 也會無法判定當前區域狀態; 所以, 最后可以嘗試重置模擬器. 

七. (反)地理編碼:

1. 概念解釋:

 地理編碼: 是指根據地址關鍵字, 將其轉換成為對應的經緯度等信息;
發地理編碼: 是指根據經緯度信息, 將其轉換成為對應的省市區街道等信息。

 

2. 地理編碼:

  1. 導入CoreLocation框架以及對應的主頭文件:

    1 #import <CoreLocation/CoreLocation.h>

     

  2. 創建CLGeocoder對象:

    self.geoC = [[CLGeocoder alloc] init];
    

     

  3. 根據地址關鍵字, 進行地理編碼:

     1 // 直接根據地址進行地理編碼(返回結果可能有多個,因為一個地點有重名)
     2  [self.geoC geocodeAddressString:@"廣州" completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) 
     3  {
     4      // 包含區,街道等信息的地標對象
     5      CLPlacemark *placemark = [placemarks firstObject];
     6      // 城市名稱
     7      NSString *city = placemark.locality;
     8      // 街道名稱
     9      NSString *street = placemark.thoroughfare;
    10      // 全稱
    11      NSString *name = placemark.name;
    12  }]; 

     


 

3. 反地理編碼:

  1. 導入CoreLocation框架以及對應的主頭文件:

    1 #import <CoreLocation/CoreLocation.h>

     

  2. 創建CLGeocoder對象:

    1 self.geoC = [[CLGeocoder alloc] init];

     

  3. 根據經緯度信息, 進行反地理編碼:

     1 // 根據經緯度信息進行反地理編碼
     2  [self.geoC reverseGeocodeLocation:[[CLLocation alloc] initWithLatitude:21.123 longitude:123.345] completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) 
     3  {
     4      // 包含區,街道等信息的地標對象
     5      CLPlacemark *placemark = [placemarks firstObject];
     6      // 城市名稱
     7      NSString *city = placemark.locality;
     8      // 街道名稱
     9      NSString *street = placemark.thoroughfare;
    10      // 全稱
    11      NSString *name = placemark.name;
    12  }]; 

     


 

4. CLPlacemark 地標對象詳解:

屬性名 類型 作用
location
CLLocation 類型
位置對象信息, 里面包含經緯度, 海拔等
region
CLRegion 類型
地標對象對應的區域
addressDictionary
NSDictionary 類
存放街道,省市等信息
name
NSString 類型
地址全稱
thoroughfare
NSString 類型
街道名稱
locality
NSString 類型
城市名稱
administrativeArea
NSString 類型
省名稱
country
NSString 類型
國家名稱
 

 

5. 測試環境:

 ①、必須聯網; ②、XCode版本不限; ③、iOS模擬器系統版本不限。 

 

6. 常見問題:

1. 測試無數據? 首先, 檢查是否有聯網; 其次, 如果是反地理編碼,可嘗試更換經緯度再次嘗試, 有的經緯度沒有對應信息。 

 

7. 應用場景:

1. 一般與定位結合使用, 確定當前位置的具體地理信息。 

八. 使用第三方框架進行定位:

1. 主要原因:

 因為使用CoreLocation框架進行獲取用戶位置信息, 是通過代理進行回調; 而第三方框架將"代理模擬"轉換成為"block模式"; 使用起來比較方便, 而且額外增加了超時時間等功能. 

 

2. 框架信息:

 名稱: locationManager 地址: [link](https://github.com/intuit/LocationManager) 

 

3. 使用方法:

 參照該框架對應的 readME。 

 

4. 注意事項:

 一般集成第三方框架到項目中, 請先確保該框架沒有問題, 然后再向項目中集成。 

九. 補充:

  1. 代理模式到block模式的轉換:

     主要思想就是,先記錄下外界傳遞過來的block, 然后在對應的代理方法里面執行這個block; 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM