最近項目中遇到需要通過MKMapView和CLLocation進行定位和商鋪顯示的需求,這幾天把這些零散的知識點總結了一下,方便日後回顧。這篇博文主要先回顧Core Location相關內容。
先雙手奉上demo代碼。
演示效果
Core Location是iOS2.0及之後用來定位的框架,在iOS3.0後加入了定位手機方向的API。Core Location能夠定位到用戶的位置靠的是Wifi定位,蜂窩基站定位和GPS定位。具體的定位方式不需要開發者考慮,iPhone會根據不同場景選擇不同定位方式。
那下面我們就來用示例程序看一下在項目中Core Location應該怎麼結合進去。
CLLocationManager
首先,我們需要創建一個CLLocation服務的管理者CLLocationManager,設置代理。(當然,在這之前需要導入頭文件CoreLocation/CoreLocation.h)
self.locMgr = [[CLLocationManager alloc] init]; self.locMgr.delegate = self;
我們可以使用startUpdatingLocation和stopUpdatingLocation來開始和結束定位.
[self.locMgr startUpdatingLocation]; [self.locMgr stopUpdatingLocation];
當成功獲取到用戶位置時,會通過回調函數通知控制器(調用頻率非常頻繁,在適當的時候應調用stopUpdatingLocation方法停止更新用戶位置或者設置CLLocationManager的distanceFilter屬性來對距離的改變進行篩選,即篩選設定距離以內的變化不會產生回調)
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
我們還可以通過設置desiredAccuracy屬性來設置定位精度,我們可以將精度設為以下常量:
extern const CLLocationAccuracy kCLLocationAccuracyBestForNavigation; extern const CLLocationAccuracy kCLLocationAccuracyBest; extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters; extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters; extern const CLLocationAccuracy kCLLocationAccuracyKilometer; extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;
大概第一步完成是這樣子的:
@interface ViewController () @property (strong, nonatomic) CLLocationManager *locMgr; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.locMgr = [[CLLocationManager alloc] init]; self.locMgr.delegate = self; self.locMgr.desiredAccuracy = kCLLocationAccuracyBestForNavigation; self.locMgr.distanceFilter = 50; [self.locMgr startUpdatingLocation]; } - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { NSLog(@"%@", locations); } @end
運行程序,卻出現了一個問題,在iOS7上會彈出詢問用戶是否允許導航的提示,但是在iOS8中卻不會出現。
提示
或許是因為iOS8對安全的要求更嚴格了(是因為iCloud洩密出去艷照的原因?),需要開發者通過代碼手動去請求定位許可(WhenInUseAuthorization或AlwaysAuthorization):
if ([self.locMgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) { [self.locMgr requestWhenInUseAuthorization]; // [self.locMgr requestAlwaysAuthorization]; } // 也可以判斷當前系統版本是否大於8.0,大於8.0時進行請求 // if ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0) { // [self.locMgr requestWhenInUseAuthorization]; // }
光這樣設置了還不夠,運行程序依然沒辦法獲得提示,我們需要到Info.plist裡面配置一下(添加一項NSLocationWhenInUseUsageDescription或NSLocationAlwaysUsageDescription,根據不同項目需要選擇)
配置完成後就能夠在iOS8下看到提示了。
定位授權判斷
在使用時我們需要判斷程序定位功能是否被開啟要怎麼做呢?我們使用系統提供的[CLLocationManager locationServicesEnabled]這個方法。。。當然是不行的!!!這個方法僅僅判斷了系統的定位服務是否開啟,不能判斷應用,所以我用了下面的方法進行判斷:
/** * 判斷定位授權 */ - (void)locationAuthorizationJudge { CLAuthorizationStatus status = [CLLocationManager authorizationStatus]; if (status == kCLAuthorizationStatusNotDetermined) { // 如果授權狀態還沒有被決定就彈出提示框 } else if (status == kCLAuthorizationStatusDenied) { // 如果授權狀態是拒絕就給用戶提示 } else if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways) { // 如果授權狀態可以使用就開始獲取用戶位置 } }
地理編碼與反地理編碼
地理編碼主要用於把用戶輸入的內容轉換成詳細坐標的方法,而反地理編碼則是通過輸入經緯度來獲取相對應的位置信息。兩者的實現都需要地理編碼器CLGeocoder。
在介紹地理編碼與反地理編碼之前先說下CLPlacemark這個類。從名稱就可以看出,CLPlacemark是用來表示地標的類,包含的參數有:cllocation,name(地標名),addressDictionary(A dictionary containing the Address Book keys and values for the placemark),country,locality等等。
- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
地理編碼調用方法,返回一個placemarks的數組和一個NSError的對象。數組中存放的是CLPlacemark的對象。為什麼會返回一個數組?因為同名的地方可能會有多個,例如“帝都”:
- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
至於反地理編碼,可以調用這個方法,將具體的經緯度坐標整合成CLLocation對象,和地理編碼一樣,完成後也會返回一個placemarks的數組和一個NSError的對象。具體效果看前面的演示吧。
模擬器定位
關於模擬器定位我這邊的做法是給一個默認的位置,這個可以按照下圖進行設置,我選的模擬位置是香港。
部分需要配合真機測試的一些功能在這裡就不展開了,感興趣的童鞋可以研究下。