定位demo(Obj-C)

weixin_34208283發表於2016-07-10

需要匯入<CoreLocation/CoreLocation.h>標頭檔案
補充說明,匯入標頭檔案後,系統會自動幫助匯入CoreLocation框架

操作步驟:
1.建立管理者(CLLocationManager)
2.請求授權 (request) 需要設定info.plist
3.設定代理,獲取資料(需要強引用)
4.開始定位 (startUpdatingLocation)
5.didUpdateLocations代理方法

1).底層獲取資料在子執行緒,使用時在主執行緒,蘋果自動幫助開發者做了執行緒管理
2).存在延遲,所以位置管理者需要強引用
3).該方法會持續的返回位置資訊,無論位置是否發生改變,停止定位:stopUpdatingLocation

  • 建立位置管理者 統一管理位置服務(manager設定強引用)
//位置管理者
@property (nonatomic, strong) CLLocationManager *mgr;
self.manager = [[CLLocationManager alloc] init];
  • 請求授權
1).WhenInUseAuthorization (前臺)
2).AlwaysAuthorization (前後臺都可以)
3).後臺模式/前臺+臨時後臺(配合NSLocationWhenInUseUsageDescription使用)

還需要設定info.plist 新增
NSLocationWhenInUseUsageDescription 使用時
NSLocationAlwaysUsageDescription 前後臺

//requestWhenInUseAuthorization是 IOS 8.0開始支援,如果相容低版本,先判斷能否響應requestWhenInUseAuthorization方法
if ([self.manager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
    
    [self.manager requestWhenInUseAuthorization];

}

前臺:


2209298-3e541ef911c64817.png
whenInUse.png

始終(前後臺):

2209298-6773d719656eacce.png
always.png

臨時後臺:開啟臨時後臺設定:

2209298-88993498a5ac8c79.png
background.png

IOS 9以後 後臺或臨時後臺除了要設定info.plist檔案外
都還需要程式碼允許後臺模式,這樣的好處是將不同的需求分離開,可以更省電(不同的位置管理者分開設定是否允許後臺)

始終:NSLocationAlwaysUsageDescription
臨時:NSLocationWhenInUseUsageDescription
self.manager.allowsBackgroundLocationUpdates = YES;
2209298-a67ce0ef9dd481a4.png
Authorization.png
  • 獲取資料 設定代理 遵循協議 實現代理方法
@interface ViewController ()<CLLocationManagerDelegate>
self.manager.delegate = self;
/**
 *  當已經獲取定位資訊後呼叫,該方法會持續返回位置資訊(無論位置是否發生變化)
 *
 *  @param manager   位置管理者
 *  @param locations 陣列<位置物件>
 */
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
    //CLLocation 位置物件
    CLLocation *location = locations.lastObject;
    //列印座標(經緯度)
    NSLog(@"%f, %f", location.coordinate.latitude, location.coordinate.longitude);
    //[manager stopUpdatingLocation];停止定位(一次性定位)

}
  • 開始定位
[self.manager startUpdatingLocation];
  • 定位操作耗時耗電,位置不改變的時候不需要持續定位,位置改變再開啟定位,所以還需要優化持續化定位
    距離篩選器 (distanceFilter) 減少不必要的代理回撥
// 距離篩選器(單位: 米)  當距離沒有超出設定範圍內,就不會有回撥
self.manager.distanceFilter = 100;

期望精確度 (desiredAccuracy) 減少不必要的能耗(精確度越低,精確度越低,能耗也越少)

/*
 extern const CLLocationAccuracy kCLLocationAccuracyBestForNavigation __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0);
 extern const CLLocationAccuracy kCLLocationAccuracyBest;
 extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;
 extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;
 extern const CLLocationAccuracy kCLLocationAccuracyKilometer;
 extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;
 */
// 期望精確度
self.manager.desiredAccuracy = kCLLocationAccuracyBest;
  • 無法獲取定位的原因:
    1.沒有設定info.plist
    2.mgr設定強引用
    3.模擬器bug 切換同iOS版本的模擬器
  • 完整程式碼:
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
@interface ViewController () <CLLocationManagerDelegate>
@property (nonatomic,strong) CLLocationManager *manager;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 建立位置管理者
    self.manager = [[CLLocationManager alloc]init];
    
    // 請求授權
    if ([self.manager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
        
        [self.manager requestWhenInUseAuthorization];
    }
    
    // 設定代理
    self.manager.delegate = self;
    
    // 開啟定位
    [self.manager startUpdatingLocation];
  
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
    
    CLLocation *location = locations.lastObject;
    NSLog(@"%f,%f",location.coordinate.latitude,location.coordinate.longitude);
    
    //[manager stopUpdatingLocation];停止定位(一次性定位)
    
}
  • 計算兩個位置間距離(直線距離):
CLLocation *location1 = [[CLLocation alloc]initWithLatitude:39.2 longitude:40.2];
CLLocation *location2 = [[CLLocation alloc]initWithLatitude:23.2 longitude:234.2];
CLLocationDistance distance = [location1 distanceFromLocation:location2];
NSLog(@"%f",distance);
  • CLLocation 位置物件屬性說明:
 //  經緯度
 @property(readonly, nonatomic) CLLocationCoordinate2D coordinate;
 //  海拔,高度
 @property(readonly, nonatomic) CLLocationDistance altitude;
 //  水平精確度  用於描述經緯度測量值和真實值之間的誤差範圍
 @property(readonly, nonatomic) CLLocationAccuracy horizontalAccuracy;
 //  垂直精確度   用於描述高度測量值和真實值之間的誤差範圍
 @property(readonly, nonatomic) CLLocationAccuracy verticalAccuracy;
 //  航向
 @property(readonly, nonatomic) CLLocationDirection course __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_2_2) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
 //  瞬時速度
 @property(readonly, nonatomic) CLLocationSpeed speed __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_2_2) __TVOS_PROHIBITED __WATCHOS_PROHIBITED;
 //  時間戳
 @property(readonly, nonatomic, copy) NSDate *timestamp;
 //  樓層 (iPhone 6 增加了氣壓感測器,之前只能通過海拔估算)
 @property(readonly, nonatomic, copy, nullable) CLFloor *floor  __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_8_0);
 //  描述
 @property (nonatomic, readonly, copy) NSString *description;