CLLocationManager類的作用是監聽GPS的位置訊息,當使用者座標發生變化時,會調用下面的方法進行通知:
-(void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation;
問題來了,當我們把newLocation中的座標映射到MKMapView控制項上時,會發現這個點跟本不是我們所在的位置,而是離我們百米左右的某個地方。
至於原因,。
那麼,我們需要將原始的(真實的)位置座標,轉換為有中國特色的座標。
對於這個問題,本文總結了兩個處理辦法:
1. 使用IOS的私人類MKLocationManager來計算。
這個做法是有風險的,蘋果不允許私人模組被直接調用。換句話說,你的軟體可能會被Deny。
因為是私人模組,我們需要聲明這個類和我們要用到的函數,代碼如下
@interface MKLocationManager + (id)sharedLocationManager; // 建立並擷取MKLocationManager執行個體 - (BOOL)chinaShiftEnabled; // 判斷IOS系統是否支援計算位移 - (CLLocation*)_applyChinaLocationShift:(CLLocation*)arg; // 傳入原始位置,計算位移後的位置@end
在CLLocationManager的位置監聽函數中,我們把newLocation(原始位置),轉換為中國位置
-(void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{ if ([[MKLocationManager sharedLocationManager] chinaShiftEnabled]) { newLocation = [[MKLocationManager sharedLocationManager] _applyChinaLocationShift:newLocation]; if (newLocation == nil) { // 很重要,計算location好像是要連網的,軟體剛啟動時前幾次計算會返回nil。 return; } }
...}
這樣,經轉換後的newLocation,已經是中國的位置了。現在在映射到MKMapView上時,會顯示正確的所在位置。
2. 開啟MKMapView的showsUserLocation功能。
初始化MKMapView時,將屬性showsUserLocation設定為YES,MKMapView會啟動內建的位置監聽服務,當使用者位置變化時,調用delegate的回呼函數:
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{ // 這裡得到的userLocation,已經是位移後的位置了}
這個方法不會用到IOS的私人類和函數,不會有被絕的風險。缺點可能是不能像CLLocationManager那樣進行豐富的配置,至少目前我還沒找到。