iOS開發者使用CoreLocation.framework框架進行定位很是簡單CoreLocation框架的經常使用API主要有以下幾個。ios
CLLocationManager定位管理器類。git
CLLocationManagerdelegate該協議表明定位管理器的delegate協議。實現該協議的對象可負責處理CLLocationManager的定位事件。程序員
CLLocation該對象表明位置。該對象包含了當前設備的經度、緯度、高度、速度、路線等信息還包含了該定位信息的水平精確度、垂直精確度以及時間戳信息。app
CLHeading該對象表明設備的移動方向。框架
CLRegion該對象表明一個區域。通常程序不會直接使用該類而是使用它的兩個子類即CLCircularRegion圓形區域和CLBeaconRegion藍牙信號區。ide
除此以外CoreLocation框架還涉及一個CLLocationCoordinate2D結構體變量該結構體變量包含經度、緯度兩個值。其中CLLocation對象的coordinate屬性就是一個CLLocationCoordinate2D結構體變量。測試
瞭解CoreLocation提供的這些API以後接下來便可經過這些API進行定位了。atom
使用CoreLocation.framework進行定位只要以下3步便可。spa
建立CLLocationManager對象該對象負責獲取定位相關信息。併爲該對象設置一些必要的屬性。.net
爲CLLocationManager指定delegate屬性該屬性值必須是一個實現CLLocationManagerDelegate協議的對象。實現CLLocationManagerDelegate協議時可根據須要實現協議中特定的方法。
調用CLLocationManager的startUpdatingLocation方法獲取定位信息。定位結束時可調用stopUpdatingLocation方法結束獲取定位信息。
注意
爲了在iOS應用中使用CoreLocation.framework須要完成兩件事情①爲應用添加CoreLocation.framework框架②在須要使用定位服務及相關類的源文件中使用「#import <CoreLocation/CoreLocation.h>」導入CoreLocation.framework的頭文件。本章絕大部分示例都使用了CoreLocation.framework所以都須要執行上面兩步操做。
從上面介紹不難看出使用CoreLocation進行定位的關鍵就是CLLocationManager對象及其delegate對象。其中CLLocationManager負責獲取定位信息而delegate則負責處理定位事件——經過這些事件便可獲取設備所在位置。
CLLocationManager還提供了以下類方法來判斷當前設備的定位相關服務狀態。
+ locationServicesEnabled返回當前定位服務是否可用。
+ deferredLocationUpdatesAvailable返回延遲定位更新是否可用。
+ significantLocationChangeMonitoringAvailable返回重大位置改變監聽是否可用。
+ headingAvailable返回該設備是否支持磁力計計算方向。
+ isRangingAvailable返回藍牙信號範圍服務是否可用。這是iOS 7新增的方法。
除此以外在使用CLLocationManager開始定位以前還可爲該對象設置以下屬性。
pausesLocationUpdatesAutomatically設置iOS設備是否可暫停定位來節省電池的電量。若是該屬性設爲「YES」則當iOS設備再也不須要定位數據時iOS設備能夠自動暫停定位。
distanceFilter設置CLLocationManager的自動過濾距離。也就是說只有當設備在水平方向的位置改變超過該數值以米爲單位指定的距離時纔會生成一次位置改變的信號。
desiredAccuracy設置定位服務的精度。該屬性值支持kCLLocationAccuracyBestForNavigation導航級的最佳精確度、kCLLocationAccuracyBest最佳精確度、kCLLocationAccuracy NearestTenMeters10米偏差、kCLLocationAccuracyHundredMeters百米偏差、kCLLocationAccuracyKilometer公里偏差、kCLLocationAccuracyThreeKilometers三公里偏差等常量值。固然也可直接指定一個浮點數做爲定位服務容許的偏差。
activityType設置定位數據的用途。該屬性支持CLActivityTypeOther定位數據做爲普通用途、CLActivityTypeAutomotiveNavigation定位數據做爲車輛導航使用、CLActivityTypeFitness定位數據做爲步行導航使用和CLActivityTypeOtherNavigation定位數據做爲其餘導航使用這幾個枚舉值之一。
接下來經過示例來示範使用CoreLocation定位iOS設備的位置。
建立一個Single View Application該項目包含一個應用程序委託類、一個視圖控制器類和Main.storyboard界面設計文件。打開該項目的界面設計文件向其中添加5個文本框分別用於顯示當前設備的經度、緯度、高度、速度和方向並在界面上添加一個UIButton按鈕。
爲了在程序中訪問界面上的5個文本框須要將它們分別綁定到視圖控制器類的longitudeTxt、latitudeTxt、altitudeTxt、speedTxt、courseTxt這5個IBOutlet屬性爲了讓程序能響應按鈕的點擊事件還須要爲按鈕的「Touch Up Inside」事件綁定bnTapped:事件處理方法。
下面是該視圖控制器類的實現部分代碼。
程序清單codes/09/9.2/LocationTest/LocationTest/FKViewController.m
@interface FKViewController () <CLLocationManagerDelegate> @property (strong,nonatomic)CLLocationManager *locationManager; @end @implementation FKViewController - (void)viewDidLoad { [super viewDidLoad]; // 建立CLLocationManager對象 self.locationManager = [[CLLocationManager alloc]init]; } - (IBAction)bnTapped:(id)sender { // 若是定位服務可用 if([CLLocationManager locationServicesEnabled]) { NSLog( @"開始執行定位服務" ); // 設置定位精度最佳精度 self.locationManager.desiredAccuracy = kCLLocationAccuracyBest; // 設置距離過濾器爲50米表示每移動50米更新一次位置 self.locationManager.distanceFilter = 50; // 將視圖控制器自身設置爲CLLocationManager的delegate // 所以該視圖控制器須要實現CLLocationManagerDelegate協議 self.locationManager.delegate = self; // 開始監聽定位信息 [self.locationManager startUpdatingLocation]; } else { NSLog( @"沒法使用定位服務" ); } } // 成功獲取定位數據後將會激發該方法 -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { // 獲取最後一個定位數據 CLLocation* location = [locations lastObject]; // 依次獲取CLLocation中封裝的經度、緯度、高度、速度、方向等信息 self.latitudeTxt.text = [NSString stringWithFormat:@"%g", location.coordinate.latitude]; self.longitudeTxt.text = [NSString stringWithFormat:@"%g", location.coordinate.longitude]; self.altitudeTxt.text = [NSString stringWithFormat:@"%g", location.altitude]; self.speedTxt.text = [NSString stringWithFormat:@"%g", location.speed]; self.courseTxt.text = [NSString stringWithFormat:@"%g", location.course]; } // 定位失敗時激發的方法 - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { NSLog(@"定位失敗: %@",error); } @end
上面程序中的第1段粗體字代碼爲CLLocationManager對象設置了屬性以後關鍵是將該視圖控制器設置爲CLLocationManager的delegate程序調用CLLocationManager的startUpdatingLocation方法開始獲取定位數據。
因爲程序指定該視圖控制器做爲CLLocationManager的delegate所以該視圖控制器須要實現CLLocationManagerDelegate協議並實現該協議中定位相關的兩個事件處理方法。當程序成功獲取定位數據時將會激發delegate的locationManager:didUpdateLocations:方法所以上面視圖控制器類實現了該方法並在該方法中獲取最後一個定位數據CLLocation對象。
CLLocation對象中包含以下屬性這些屬性包含了定位相關信息。
altitude該屬性表示當前設備的海拔高度單位是米。
coordinate該屬性返回一個CLLocationCoordinate2D結構體變量該結構體變量中包含經度、緯度信息。
course該屬性表示當前設備前進的方向。該值爲0°表示向北90°表示向東180°表示向南270°表示向西。
horizontalAccuracy該屬性代表定位信息的水平精確度。將返回的座標做爲圓心並將水平精確度視爲半徑。真正的設備位置落在此圓內的某處。此圓越小位置就越精確此圓越大則位置越不精確。若是精確度爲負值則代表測量精確度失敗。
verticalAccuracy該屬性代表定位信息的垂直精確度。也就是說iOS設備的實際高度在該定位信息的高度加或減該屬性值的範圍內。
timestamp該屬性返回定位信息的返回時間。
speed該屬性表示返回設備的移動速度單位是米/秒。實際上該屬性適用於行車速度而不太適用於步行速度。
每一個 iOS 應用第一次使用定位功能時都會由於權限問題而彈出是否容許當前應用程序獲取定位操做權限的提示框如圖 9.1 所示。圖9.1 詢問用戶是否容許該應用使用定位功能
單擊「OK」按鈕便可在Xcode控制器中看到「開始執行定位服務」的提示信息但可能依然看不到程序界面上有任何輸出——此時咱們能夠經過模擬器來模擬設備的位置。
iOS模擬器自己並不能做爲GPS接收機所以沒法獲得定位信息但爲了方便程序員測試定位應用iOS模擬器能夠模擬定位信息。
啓動iOS模擬器以後便可經過iOS模擬器主菜單中的「調試」→「位置」來模擬iOS設備的位置該菜單如圖9.2所示。
圖9.2所示菜單支持以下幾種位置信息。
自定位置開發者能夠自行輸入位置的經度值、緯度值。
City Bicycle Ride模擬設備攜帶者在城市中騎車移動。
City Run模擬設備攜帶者在城市中跑動。
Freeway Drive模擬設備攜帶者在高速公路中駕車。
若是選擇「Freeway Driver」來模擬該設備攜帶者在高速公路中駕車則能夠看到該應用顯示如圖9.3所示。
上一個示例是經過CLLocation對象來獲取設備的移動速度和移動方向但這種移動速度屬性適用於行車速度而不太適用於步行速度。若是但願程序計算平均移動速度則只要不斷地累計設備的移動距離和移動時間再用距離除以時間便可獲得設備的平均移動速度。
下面經過一個示例來計算設備的平均移動速度。新建一個Single View Application打開該應用的Main.storyboard界面設計文件向該界面設計文件中拖入一個UITextView控件用於顯示該設備的移動速度。爲了在程序中訪問該UITextView控件程序將它綁定到視圖控制器的showView控件。
接下來修改視圖控制器類在視圖控制器類中經過設備的移動距離和移動時間來計算速度。下面是該視圖控制器類的實現部分代碼。
程序清單codes/09/9.2/SpeedMonitor/SpeedMonitor/FKViewController.m
#import "FKViewController.h" #import <CoreLocation/CoreLocation.h> @interface FKViewController () <CLLocationManagerDelegate> @property (nonatomic , retain) CLLocationManager *locationManager; @property (nonatomic , retain) CLLocation *prevLocation; @property (nonatomic , assign) CGFloat sumDistance; @property (nonatomic , assign) CGFloat sumTime; @end @implementation FKViewController - (void) viewDidLoad { [super viewDidLoad]; // 建立CLLocationManager對象 self.locationManager = [[CLLocationManager alloc] init]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // 設置定位精度最佳精度 self.locationManager.desiredAccuracy = kCLLocationAccuracyBest; // 設置距離過濾器爲50米表示每移動50米更新一次位置 self.locationManager.distanceFilter = 50; // 將視圖控制器自身設置爲CLLocationManager的delegate // 所以該視圖控制器須要實現CLLocationManagerDelegate協議 self.locationManager.delegate = self; // 開始監聽定位信息 [self.locationManager startUpdatingLocation]; NSLog(@"開始執行定位服務" ); } // 定位失敗時激發的方法 - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { NSLog(@"定位失敗: %@",error); } // 成功獲取定位數據後將會激發該方法 -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { // 獲取最後一個定位數據 CLLocation* newLocation = [locations lastObject]; if(newLocation.horizontalAccuracy < kCLLocationAccuracyHundredMeters) { if(self.prevLocation) { // 計算本次定位數據與上次定位數據之間的時間差 NSTimeInterval dTime = [newLocation.timestamp timeIntervalSinceDate:self.prevLocation.timestamp]; // 累計行車時間 self.sumTime += dTime; // 計算本次定位數據與上次定位數據之間的距離 CGFloat distance = [newLocation distanceFromLocation:self.prevLocation]; // 若是距離小於1米則忽略本次數據直接返回該方法 if(distance < 1.0f) { return; } // 累加移動距離 self.sumDistance += distance; // 計算移動速度將米/秒換算成公里/小時須要乘以3.6 CGFloat speed = distance / dTime * 3.6; // 計算平均速度 CGFloat avgSpeed = self.sumDistance / self.sumTime * 3.6; NSString * speedFeedback = [NSString stringWithFormat: @"當前速度爲%g公里/小時平均速度爲:%g公里/小時。合計移動:%g公里", speed , avgSpeed , self.sumDistance / 1000]; self.showView.text = speedFeedback; } self.prevLocation = newLocation; } } @end
上面程序中的兩行粗體字代碼分別用於計算本次定位數據與上次定位數據之間的時間差、距離用此距離除以時間便可獲得該設備的當前速度。除此以外該程序還定義了一個sumDistance屬性來保存設備移動的總距離並定義了一個sumTime來保存設備移動的總時間用設備移動的總距離除以設備移動的總時間便可獲取該設備移動的平均速度。
提示
iOS系統獲取的先後兩次定位數據的時間差以秒爲單位先後兩次定位數據之間的距離以米爲單位所以直接用距離除以時間獲得速度單位爲米/秒。若是程序但願以公里/小時做爲速度單位則須要乘以3.6。
編譯、運行該程序並選擇「Freeway Driver」來模擬設備攜帶者在高速公路中駕車將能夠看到該應用顯示如圖9.4所示的結果。
————本文節選自《瘋狂ios講義下》