iOS開發 - CoreLocation地理定位

來源:互聯網
上載者:User

iOS開發 - CoreLocation地理定位
簡介

在移動互連網時代,移動app能解決使用者的很多生活瑣事,比如
導航:去任意陌生的地方
周邊:找餐館、找酒店、找銀行、找電影院

在上述應用中,都用到了地圖和定位功能,在iOS開發中,要想加入這2大功能,必須基於2個架構進行開發
Map Kit :用於地圖展示
Core Location :用於地理定位

2個熱門專業術語
LBS :Location Based Service
SoLoMo :Social Local Mobile(索羅門)

CoreLocation架構的使用

CoreLocation架構使用前提
匯入架構

匯入主標頭檔

#import 

CoreLocation架構使用須知
CoreLocation架構中所有資料類型的首碼都是CL
CoreLocation中使用CLLocationManager對象來做使用者定位

CLLocationManager
CLLocationManager的常用操作//開始使用者定位- (void)startUpdatingLocation;//停止使用者定位- (void) stopUpdatingLocation;//當調用了startUpdatingLocation方法後,就開始不斷地定位使用者的位置,中途會頻繁地調用代理的下面方法- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;locations參數裡面裝著CLLocation對象@property(assign, nonatomic) CLLocationDistance distanceFilter;//每隔多少米定位一次@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;//定位精確度(越精確就越耗電)
CLLocation

CLLocation用來表示某個位置的地理資訊,比如經緯度、海拔等等

@property(readonly, nonatomic) CLLocationCoordinate2D coordinate;//經緯度@property(readonly, nonatomic) CLLocationDistance altitude;//海拔@property(readonly, nonatomic) CLLocationDirection course;//路線,航向(取值範圍是0.0° ~ 359.9°,0.0°代表真北方向)@property(readonly, nonatomic) CLLocationSpeed speed;//行走速度(單位是m/s)用- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location方法可以計算2個位置之間的距離
CLLocationCoordinate2D
CLLocationCoordinate2D是一個用來表示經緯度的結構體,定義如下typedef struct {        CLLocationDegrees latitude; // 緯度        CLLocationDegrees longitude; // 經度} CLLocationCoordinate2D;//一般用CLLocationCoordinate2DMake
使用者隱私的保護

從iOS 6開始,蘋果在保護使用者隱私方面做了很大的加強,以下操作都必須經過使用者批准授權
要想獲得使用者的位置
想訪問使用者的通訊錄、日曆、相機、相簿等等

當想訪問使用者的隱私資訊時,系統會自動彈出一個對話方塊讓使用者授權

開發人員可以在Info.plist中設定NSLocationUsageDescription說明定位的目的(Privacy - Location Usage Description)

一旦使用者選擇了“Don’t Allow”,意味著你的應用以後就無法使用定位功能
為了嚴謹起見,最好在使用定位功能之前判斷當前應用的定位功能是否可用
//CLLocationManager有個類方法可以判斷當前應用的定位功能是否可用
+ (BOOL)locationServicesEnabled;

CLGeocoder

使用CLGeocoder可以完成“地理編碼”和“反地理編碼”
地理編碼:根據給定的地名,獲得具體的位置資訊(比如經緯度、地址的全稱等)
反地理編碼:根據給定的經緯度,獲得具體的位置資訊

//地理編碼方法- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;//反地理編碼方法- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
CLGeocodeCompletionHandler
//當地理反地理編碼完成時,就會調用CLGeocodeCompletionHandlertypedef void (^CLGeocodeCompletionHandler)(NSArray *placemarks, NSError *error);這個block傳遞2個參數error :當編碼出錯時(比如編碼不出具體的資訊)有值placemarks :裡面裝著CLPlacemark對象
標題

CLPlacemark的字面意思是地標,封裝詳細的地址位置資訊

@property (nonatomic, readonly) CLLocation *location;//地理位置@property (nonatomic, readonly) CLRegion *region;//地區@property (nonatomic, readonly) NSDictionary *addressDictionary;//詳細的地址資訊@property (nonatomic, readonly) NSString *name;//位址名稱@property (nonatomic, readonly) NSString *locality;//城市
關係圖

CoreLocation執行個體
@interface ViewController ()/** *  定位管理者 */@property (nonatomic ,strong) CLLocationManager *mgr;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // 1.建立CoreLocation管理者    CLLocationManager *mgr = [[CLLocationManager alloc] init];    // 2.成為CoreLocation管理者的代理監聽擷取到的位置    self.mgr.delegate = self;    // 設定多久擷取一次    self.mgr.distanceFilter = 500;    // 設定擷取位置的精確度    /*      kCLLocationAccuracyBestForNavigation 最佳導航      kCLLocationAccuracyBest;  最精準      kCLLocationAccuracyNearestTenMeters;  10米      kCLLocationAccuracyHundredMeters;  百米      kCLLocationAccuracyKilometer;  千米      kCLLocationAccuracyThreeKilometers;  3千米     */    self.mgr.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;    // 判斷是否是iOS8    if([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0)    {        NSLog(@是iOS8);        // 主動要求使用者對我們的程式授權, 授權狀態改變就會通知代理        //        [self.mgr requestAlwaysAuthorization]; // 請求前台和後台定位許可權//        [self.mgr requestWhenInUseAuthorization];// 請求前台定位許可權    }else    {        NSLog(@是iOS7);        // 3.開始監聽(開始擷取位置)        [self.mgr startUpdatingLocation];    }}/** *  授權狀態發生改變時調用 * *  @param manager 觸發事件的對象 *  @param status  當前授權的狀態 */- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{    /*     使用者從未選擇過許可權     kCLAuthorizationStatusNotDetermined     無法使用定位服務,該狀態使用者無法改變     kCLAuthorizationStatusRestricted     使用者拒絕該應用使用定位服務,或是定位服務總開關處於關閉狀態     kCLAuthorizationStatusDenied     已經授權(廢棄)     kCLAuthorizationStatusAuthorized     使用者允許該程式無論何時都可以使用地理資訊     kCLAuthorizationStatusAuthorizedAlways     使用者同意程式在可見時使用地理位置     kCLAuthorizationStatusAuthorizedWhenInUse     */    if (status == kCLAuthorizationStatusNotDetermined) {        NSLog(@等待使用者授權);    }else if (status == kCLAuthorizationStatusAuthorizedAlways ||              status == kCLAuthorizationStatusAuthorizedWhenInUse)    {        NSLog(@授權成功);        // 開始定位        [self.mgr startUpdatingLocation];    }else    {        NSLog(@授權失敗);    }}#pragma mark - CLLocationManagerDelegate//- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation/** *  擷取到位置資訊之後就會調用(調用頻率非常高) * *  @param manager   觸發事件的對象 *  @param locations 擷取到的位置 */- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{    NSLog(@%s, __func__);    // 如果只需要擷取一次, 可以擷取到位置之後就停止//    [self.mgr stopUpdatingLocation];}#pragma mark - 懶載入- (CLLocationManager *)mgr{    if (!_mgr) {        _mgr = [[CLLocationManager alloc] init];    }    return _mgr;}@end
    /*     注意: iOS7隻要開始定位, 系統就會自動要求使用者對你的應用程式授權. 但是從iOS8開始, 想要定位必須先自己主動要求使用者授權      在iOS8中不僅僅要主動請求授權, 而且必須再info.plist檔案中配置一項屬性才能彈出授權視窗     NSLocationWhenInUseDescription,允許在前台擷取GPS的描述     NSLocationAlwaysUsageDescription,允許在後台擷取GPS的描述    */
@interface ViewController ()/** *  定位管理者 */@property (nonatomic ,strong) CLLocationManager *mgr;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // 1.建立CoreLocation管理者//    CLLocationManager *mgr = [[CLLocationManager alloc] init];    // 2.成為CoreLocation管理者的代理監聽擷取到的位置    self.mgr.delegate = self;    // 判斷是否是iOS8    if([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0)    {        NSLog(@是iOS8);        // 主動要求使用者對我們的程式授權, 授權狀態改變就會通知代理        [self.mgr requestAlwaysAuthorization]; // 請求前台和後台定位許可權    }else    {        NSLog(@是iOS7);        // 3.開始監聽(開始擷取位置)        [self.mgr startUpdatingLocation];    }}/** *  授權狀態發生改變時調用 * *  @param manager 觸發事件的對象 *  @param status  當前授權的狀態 */- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{   if (status == kCLAuthorizationStatusNotDetermined) {        NSLog(@等待使用者授權);    }else if (status == kCLAuthorizationStatusAuthorizedAlways ||              status == kCLAuthorizationStatusAuthorizedWhenInUse)    {        NSLog(@授權成功);        // 開始定位        [self.mgr startUpdatingLocation];    }else    {        NSLog(@授權失敗);    }}#pragma mark - CLLocationManagerDelegate/** *  擷取到位置資訊之後就會調用(調用頻率非常高) * *  @param manager   觸發事件的對象 *  @param locations 擷取到的位置 */- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{    NSLog(@%s, __func__);    // 如果只需要擷取一次, 可以擷取到位置之後就停止//    [self.mgr stopUpdatingLocation];    // 1.擷取最後一次的位置    /*     location.coordinate; 座標, 包含經緯度     location.altitude; 裝置海拔高度 單位是米     location.course; 設定前進方向 0表示北 90東 180南 270西     location.horizontalAccuracy; 水平精準度     location.verticalAccuracy; 垂直精準度     location.timestamp; 定位資訊返回的時間     location.speed; 裝置移動速度 單位是米/秒, 適用於行車速度而不太適用於不行     */    /*     可以設定模擬器類比速度     bicycle ride 騎車移動     run 跑動     freeway drive 高速公路駕車     */    CLLocation *location = [locations lastObject];    NSLog(@%f, %f speed = %f, location.coordinate.latitude , location.coordinate.longitude, location.speed);}#pragma mark - 懶載入- (CLLocationManager *)mgr{    if (!_mgr) {        _mgr = [[CLLocationManager alloc] init];    }    return _mgr;}@end
汽車導航執行個體
#import ViewController.h#import @interface ViewController ()// 建立定位管理者@property (nonatomic, strong) CLLocationManager *mgr;// 上一次的位置@property (nonatomic, strong) CLLocation *previousLocation;// 總路程@property (nonatomic, assign) CLLocationDistance  sumDistance;// 總時間@property (nonatomic, assign) NSTimeInterval  sumTime;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // 1.建立定位管理者//    CLLocationManager *mgr = [[CLLocationManager alloc] init];    // 2.設定代理    self.mgr.delegate = self;    // 3.判斷是否是iOS8    if ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0) {        // 主動請求授權        [self.mgr requestAlwaysAuthorization];    }    // 3.開始定位    [self.mgr startUpdatingLocation];}#pragma mark - CLLocationManagerDelegate- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{//    CLLocation; timestamp 當前擷取到為止資訊的時間    /*     擷取走了多遠(這一次的位置 減去上一次的位置)     擷取走這段路花了多少時間 (這一次的時間 減去上一次的時間)     擷取速度 (走了多遠 / 花了多少時間)     擷取總共走的路程 (把每次擷取到走了多遠累加起來)     擷取平均速度 (用總路程 / 總時間)     */    // 擷取當前的位置    CLLocation *newLocation = [locations lastObject];    if (self.previousLocation != nil) {        // 計算兩次的距離(單位時米)        CLLocationDistance distance = [newLocation distanceFromLocation:self.previousLocation];        // 計算兩次之間的時間(單位只秒)        NSTimeInterval dTime = [newLocation.timestamp timeIntervalSinceDate:self.previousLocation.timestamp];        // 計算速度(米/秒)        CGFloat speed = distance / dTime;        // 累加時間        self.sumTime += dTime;        // 累加距離        self.sumDistance += distance;        //  計算平均速度        CGFloat avgSpeed = self.sumDistance / self.sumTime;        NSLog(@距離%f 時間%f 速度%f 平均速度%f 總路程 %f 總時間 %f, distance, dTime, speed, avgSpeed, self.sumDistance, self.sumTime);    }    // 紀錄上一次的位置    self.previousLocation = newLocation;}//#pragma mark - 懶載入- (CLLocationManager *)mgr{    if (!_mgr) {        self.mgr = [[CLLocationManager alloc] init];    }    return _mgr;}@end
指南針執行個體
#import ViewController.h#import @interface ViewController ()/** *  定位管理者 */@property (nonatomic ,strong) CLLocationManager *mgr;// 指南針圖片@property (nonatomic, strong) UIImageView *compasspointer;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // 1.添加指南針圖片    UIImageView *iv = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@bg_compasspointer]];    iv.center = CGPointMake(self.view.center.x, self.view.center.y);    [self.view addSubview:iv];    self.compasspointer = iv;    // 2.成為CoreLocation管理者的代理監聽擷取到的位置    self.mgr.delegate = self;    // 3.開始擷取使用者位置    // 注意:擷取使用者的方向資訊是不需要使用者授權的    [self.mgr startUpdatingHeading];}#pragma mark - CLLocationManagerDelegate// 當擷取到使用者方向時就會調用- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading{//    NSLog(@%s, __func__);    /*     magneticHeading 裝置與磁北的相對角度     trueHeading 設定與真北的相對角度, 必須和定位一起使用, iOS需要設定的位置來計算真北     真北始終指向地理北極點     *///    NSLog(@%f, newHeading.magneticHeading);    // 1.將擷取到的角度轉為弧度 = (角度 * π) / 180;    CGFloat angle = newHeading.magneticHeading * M_PI / 180;    // 2.旋轉圖片    /*     順時針 正     逆時針 負數     *///    self.compasspointer.transform = CGAffineTransformIdentity;    self.compasspointer.transform = CGAffineTransformMakeRotation(-angle);}#pragma mark - 懶載入- (CLLocationManager *)mgr{    if (!_mgr) {        _mgr = [[CLLocationManager alloc] init];    }    return _mgr;}@end
地區檢查執行個體
#import ViewController.h#import @interface ViewController ()/** *  定位管理者 */@property (nonatomic ,strong) CLLocationManager *mgr;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // 2.成為CoreLocation管理者的代理監聽擷取到的位置    self.mgr.delegate = self;    // 注意:如果是iOS8, 想進列區域檢測, 必須自己主動請求擷取使用者隱私的許可權    if  ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0 )    {        [self.mgr requestAlwaysAuthorization];    }    // 3.開始檢測使用者所在的地區    // 3.1建立地區//    CLRegion 有兩個子類是專門用於指定地區的//    一個可以指定藍芽的範圍/ 一個是可以指定圓形的範圍    // 建立中心點    CLLocationCoordinate2D center = CLLocationCoordinate2DMake(40.058501, 116.304171);    // c建立圓形地區, 指定地區中心點的經緯度, 以及半徑    CLCircularRegion *circular = [[CLCircularRegion alloc] initWithCenter:center radius:500 identifier:@軟體園];    [self.mgr startMonitoringForRegion:circular];}#pragma mark - CLLocationManagerDelegate// 進入監聽地區時調用- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{    NSLog(@進入監聽地區時調用);}// 離開監聽地區時調用- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region{    NSLog(@離開監聽地區時調用);}//#pragma mark - 懶載入- (CLLocationManager *)mgr{    if (!_mgr) {        _mgr = [[CLLocationManager alloc] init];    }    return _mgr;}@end
地理編碼執行個體
#import ViewController.h#import @interface ViewController ()#pragma mark - 地理編碼/** *  監聽地理編碼點擊事件 */- (IBAction)geocodeBtnClick;/** *  需要編碼的地址容器 */@property (weak, nonatomic) IBOutlet UITextField *addressField;/** *  經度容器 */@property (weak, nonatomic) IBOutlet UILabel *longitudeLabel;/** *  緯度容器 */@property (weak, nonatomic) IBOutlet UILabel *latitudeLabel;/** *  詳情容器 */@property (weak, nonatomic) IBOutlet UILabel *detailAddressLabel;/** *  地理編碼對象 */@property (nonatomic ,strong) CLGeocoder *geocoder;@end@implementation ViewController- (void)geocodeBtnClick{    // 0.擷取使用者輸入的位置    NSString *addressStr = self.addressField.text;    if (addressStr == nil || addressStr.length == 0) {        NSLog(@請輸入地址);        return;    }    // 1.建立地理編碼對象    // 2.利用地理編碼對象編碼    // 根據傳入的地址擷取該地址對應的經緯度資訊    [self.geocoder geocodeAddressString:addressStr completionHandler:^(NSArray *placemarks, NSError *error) {        if (placemarks.count == 0 || error != nil) {            return ;        }        // placemarks地標數組, 地標數組中存放著地標, 每一個地標包含了該位置的經緯度以及城市/地區/國家代碼/郵編等等...        // 擷取數組中的第一個地標        CLPlacemark *placemark = [placemarks firstObject];//        for (CLPlacemark  *placemark in placemarks) {//            NSLog(@%@ %@ %f %f, placemark.name, placemark.addressDictionary, placemark.location.coordinate.latitude, placemark.location.coordinate.longitude);        self.latitudeLabel.text = [NSString stringWithFormat:@%f, placemark.location.coordinate.latitude];        self.longitudeLabel.text = [NSString stringWithFormat:@%f, placemark.location.coordinate.longitude];        NSArray *address = placemark.addressDictionary[@FormattedAddressLines];        NSMutableString *strM = [NSMutableString string];        for (NSString *str in address) {            [strM appendString:str];        }        self.detailAddressLabel.text = strM;//        }    }];}- (CLGeocoder *)geocoder{    if (!_geocoder) {        _geocoder = [[CLGeocoder alloc] init];    }    return _geocoder;}@end
反地理編碼執行個體
#import ViewController.h#import @interface ViewController ()/** *  地理編碼對象 */@property (nonatomic ,strong) CLGeocoder *geocoder;#pragma mark - 反地理編碼- (IBAction)reverseGeocode;@property (weak, nonatomic) IBOutlet UITextField *longtitudeField;@property (weak, nonatomic) IBOutlet UITextField *latitudeField;@property (weak, nonatomic) IBOutlet UILabel *reverseDetailAddressLabel;@end@implementation ViewController- (void)reverseGeocode{    // 1.擷取使用者輸入的經緯度    NSString *longtitude = self.longtitudeField.text;    NSString *latitude = self.latitudeField.text;    if (longtitude.length == 0 ||        longtitude == nil ||        latitude.length == 0 ||        latitude == nil) {        NSLog(@請輸入經緯度);        return;    }    // 2.根據使用者輸入的經緯度建立CLLocation對象    CLLocation *location = [[CLLocation alloc] initWithLatitude:[latitude doubleValue]  longitude:[longtitude doubleValue]];    // 3.根據CLLocation對象擷取對應的地標資訊    [self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {        for (CLPlacemark *placemark in placemarks) {            NSLog(@%@ %@ %f %f, placemark.name, placemark.addressDictionary, placemark.location.coordinate.latitude, placemark.location.coordinate.longitude);            self.reverseDetailAddressLabel.text = placemark.locality;        }    }];}//#pragma mark - 懶載入- (CLGeocoder *)geocoder{    if (!_geocoder) {        _geocoder = [[CLGeocoder alloc] init];    }    return _geocoder;}@end

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.