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那樣進行豐富的配置,至少目前我還沒找到。