11.1 iOS定位服務
11.2 iOS地圖
11.3 Web地圖
11.1 iOS定位服務
iOS中有三個定位服務組件:
Wifi定位,通過查詢一個Wifi路由器的地理位置的信息。比較省電,iPod touch和iPad也可以采用。
蜂窩基站定位,通過移動運用商基站定位。也適合有3G版本的iPod touch和iPad。
GPS衛星定位,通過3-4顆GPS定位位置定位,最為准確,但是耗電量大,不能遮擋。
Core Location
Core Location是iPhone、iPad等開發定位服務應用程序的框架。我們要在Xcode中添加“CoreLocation.framework”存在的框架。
主要使用的類是:CLLocationManager,通過CLLocationManager實現定位服務。
CoreLocation.framework
定位服務實例
項目WhereAmI:
WhereAmIViewController.h
#import <UIKit/UIKit.h> #import <CoreLocation/CoreLocation.h> @interface ViewController : UIViewController<CLLocationManagerDelegate> { CLLocationManager* locationManager; } @property (strong, nonatomic) CLLocationManager* locationManager; @property (retain, nonatomic) IBOutlet UILabel *longitudeText; @property (retain, nonatomic) IBOutlet UILabel *latituduText; @property (retain, nonatomic) IBOutlet UIActivityIndicatorView *activity; - (IBAction)findMe:(id)sender; - (IBAction)webMap:(id)sender; @end
CLLocationManagerDelegate是定位服務的委托,常用的位置變化回調方法是:
locationManager:didUpdateToLocation:fromLocation: locationManager:didFailWithError:
CLLocationManager 是定位服務管理類,通過它可以設置定位服務的參數、獲取經緯度等。
m中加載方法
- (IBAction)findMe:(id)sender { self.locationManager = [[[CLLocationManager alloc] init] autorelease]; self.locationManager.delegate = self; self.locationManager.desiredAccuracy = kCLLocationAccuracyBest; self.locationManager.distanceFilter = 1000.0f; [self.locationManager startUpdatingLocation]; [activity startAnimating]; NSLog(@"start gps"); }
CLLocationManager 是的startUpdatingLocation方法啟動所有定位硬件,對應的方法是stopUpdatingLocation,通過調用該方法關閉定位服務器更新,為了省電必須在不用的時候調用該方法關閉定位服務。
此外,我們還可以在這里設定定位服務的參數,包括:distanceFilter和desiredAccuracy。
distanceFilter,這個屬性用來控制定位服務更新頻率。單位是“米”。 desiredAccuracy,這個屬性用來控制定位精度,精度
越高耗電量越大。
定位精度
desiredAccuracy精度參數可以iOS SDK通過常量實現:
kCLLocationAccuracyNearestTenMeters,10米
kCLLocationAccuracyHundredMeters ,100米
kCLLocationAccuracyKilometer ,1000米
kCLLocationAccuracyThreeKilometers,3000米
kCLLocationAccuracyBest ,最好的精度
kCLLocationAccuracyBestForNavigation,導航情況下最好精度,iOS 4 SDK新增加。一般要有外接電源時候才能使用。
委托方法用於實現位置的更新
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { latituduText.text = [NSString stringWithFormat:@"%3.5f",newLocation.coordinate.latitude]; longitudeText.text = [NSString stringWithFormat:@"%3.5f",newLocation.coordinate.longitude]; [activity stopAnimating]; [locationManager stopUpdatingLocation]; NSLog(@"location ok"); }
該委托方法不僅可以獲得當前位置(newLocation),還可以獲得上次的位置(oldLocation ),CLLocation 對象coordinate.latitude屬性獲得經度,coordinate.longitude屬性獲得緯度。
[NSString stringWithFormat:@"%3.5f”, newLocation.coordinate.latitude] 中的%3.5f是輸出整數部分是3位,小數部分是5位的浮點數。
11.2 iOS地圖
iOS應用程序中使用Map Kit API開發地圖應用程序。
其核心是MKMapView類使用。
多數情況下地圖會與定位服務結合使用。
地圖開發一般過程
添加MapKit類庫
MapKit.framework
MapMeViewController.h
#import <UIKit/UIKit.h> #import <MapKit/MapKit.h> #import <CoreLocation/CoreLocation.h> #import "MapLocation.h" @interface ViewController : UIViewController<CLLocationManagerDelegate, MKReverseGeocoderDelegate, MKMapViewDelegate> { } @property (retain, nonatomic) IBOutlet MKMapView *mapView; @property (retain, nonatomic) IBOutlet UIActivityIndicatorView *activity; - (IBAction)findMe:(id)sender; @end
CLLocationManagerDelegate是定位服務委托。
MKMapViewDelegate是地圖視圖委托,主要方法:
-mapView:viewForAnnotation:
-mapViewDidFailLoadingMap:withError:
MKReverseGeocoderDelegate是給地理坐標獲得標志點信息的委托,用於地理信息編碼(即:從坐標獲得地點獲得信息),主要委托方法:
– reverseGeocoder:didFindPlacemark:
– reverseGeocoder:didFailWithError:
m文件中的視圖加載和卸載
- (void)viewDidLoad { [super viewDidLoad]; mapView.mapType = MKMapTypeStandard; //mapView.mapType = MKMapTypeSatellite; //mapView.mapType = MKMapTypeHybrid; mapView.delegate = self; }
mapView.mapType = MKMapTypeStandard;是指定地圖的類型,iOS提供了三種風格的地圖:
MKMapTypeStandard標准地圖模式
MKMapTypeSatellite衛星地圖模式
MKMapTypeHybrid具有街道等信息的衛星地圖模式
mapView.delegate = self;是將委托對象指定為自身。
按鈕事件
- (IBAction)findMe:(id)sender { CLLocationManager *lm = [[CLLocationManager alloc] init]; lm.delegate = self; lm.desiredAccuracy = kCLLocationAccuracyBest; [lm startUpdatingLocation]; activity.hidden = NO; [activity startAnimating]; }
點擊按鈕時候通過定位服務獲取當前位置信息。
通過lm.delegate = self;是將委托對象指定為自身。
因此,點擊事件發生時候將會回調CLLocationManagerDelegate委托的
-locationManager:didUpdateToLocation:fromLocation:方法。
回調位置更新方法
#pragma mark CLLocationManagerDelegate Methods - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(newLocation.coordinate, 2000, 2000); //[mapView setRegion:viewRegion animated:YES]; MKCoordinateRegion adjustedRegion = [mapView regionThatFits:viewRegion]; [mapView setRegion:adjustedRegion animated:YES]; manager.delegate = nil; [manager stopUpdatingLocation]; MKReverseGeocoder *geocoder = [[MKReverseGeocoder alloc] initWithCoordinate:newLocation.coordinate]; geocoder.delegate = self; [geocoder start]; }
MKCoordinateRegionMakeWithDistance(newLocation.coordinate, 2000, 2000); 該函數能夠創建一個MKCoordinateRegion結構體,第一個參數是一個CLLocationCoordinate2D結構指定了目標區域的中心點,第二個是目標區域南北的跨度單位是米,第三個是目標區域東西的跨度單位是米。后兩個參數的調整會影響地圖縮放。
[[MKReverseGeocoder alloc] initWithCoordinate:newLocation.coordinate]; 創建地理編碼對象geocoder,通過該對象可以把坐標轉換成為地理信息的描述。
geocoder.delegate = self;指定編碼的處理是自身對象。
[geocoder start];開始編碼處理。
MKReverseGeocoderDelegate
是地理編碼委托對象,該委托的方法:
成功時候調用-reverseGeocoder:didFindPlacemark:
失敗時候調用-reverseGeocoder:didFailWithError:
成功編碼回調方法
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark { MapLocation *annotation = [[MapLocation alloc] init]; annotation.streetAddress = placemark.thoroughfare; annotation.city = placemark.locality; annotation.state = placemark.administrativeArea; annotation.zip = placemark.postalCode; annotation.coordinate = geocoder.coordinate; [mapView addAnnotation:annotation]; [annotation release]; geocoder.delegate = nil; [geocoder autorelease]; [activity stopAnimating]; activity.hidden = YES; }
成功編碼后需要在該方法中創建標注對象(MapLocation)。MapLocation 是我們自定義的實現MKAnnotation協議標注對象。 該方法的placemark是MKPlacemark獲得很多地理信息,詳細見下表。
[mapView addAnnotation:annotation]; 為地圖添加標注,該方法將會觸發mapView:viewForAnnotation:方法回調。
MKPlacemark類屬性
addressDictionary 地址信息的dictionary
thoroughfare 指定街道級別信息
subThoroughfare 指定街道級別的附加信息
locality 指定城市信息
subLocality 指定城市信息附加信息
administrativeArea 行政區域
subAdministrativeArea 行政區域附加信息
country 國家信息
countryCode 國家代號
postalCode 郵政編碼
失敗編碼回調方法
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"地理解碼錯誤息" message:@"地理代碼不能識別" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil]; [alert show]; [alert release]; geocoder.delegate = nil; [geocoder autorelease]; [activity stopAnimating]; }
MKMapViewDelegate
是地圖視圖委托對象,本例子我們使用的方法:
- mapView:viewForAnnotation:為地圖設置標注時候回調方法。
-mapViewDidFailLoadingMap:withError:地圖加載錯誤時候回調方法。
地圖標注回調方法
#pragma mark Map View Delegate Methods - (MKAnnotationView *) mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>) annotation { MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"PIN_ANNOTATION"]; if(annotationView == nil) { annotationView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"PIN_ANNOTATION"] autorelease]; } annotationView.canShowCallout = YES; annotationView.pinColor = MKPinAnnotationColorRed; annotationView.animatesDrop = YES; annotationView.highlighted = YES; annotationView.draggable = YES; return annotationView; }
與表格視圖單元格處理類似,地圖標注對象由於會很多,因此需要重復利用,通過
dequeueReusableAnnotationViewWithIdentifier方法可以查找可重復利用的標注對象,以達到節省內存的目的。
annotationView.canShowCallout = YES;指定標注上的插圖,點擊圖釘有氣泡顯示。
annotationView.pinColor 設置圖釘的顏色。
annotationView.animatesDrop動畫效果。
地圖加載失敗回調方法
- (void)mapViewDidFailLoadingMap:(MKMapView *)theMapView withError:(NSError *)error { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"地圖加載錯誤" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil]; [alert show]; [alert release]; }
自定義地圖標注對象
#import <Foundation/Foundation.h> #import <MapKit/MapKit.h> @interface MapLocation : NSObject <MKAnnotation, NSCoding> { NSString *streetAddress; NSString *city; NSString *state; NSString *zip; CLLocationCoordinate2D coordinate; } @property (nonatomic, copy) NSString *streetAddress; @property (nonatomic, copy) NSString *city; @property (nonatomic, copy) NSString *state; @property (nonatomic, copy) NSString *zip; @property (nonatomic, readwrite) CLLocationCoordinate2D coordinate; @end
作為地圖標注對象實現MKAnnotation協議是必須的,只有實現該協議才能使該類成為標注類。實現NSCoding協議是可選的,實現該協議可以使標注對象能夠復制。 里面的屬性有哪些要看你自己的需要。
MapLocation.m
- (NSString *)title { return @"您的位置!"; } - (NSString *)subtitle { NSMutableString *ret = [NSMutableString string]; if (streetAddress) [ret appendString:streetAddress]; if (streetAddress && (city || state || zip)) [ret appendString:@" • "]; if (city) [ret appendString:city]; if (city && state) [ret appendString:@", "]; if (state) [ret appendString:state]; if (zip) [ret appendFormat:@", %@", zip]; return ret; }
title 和subtitle 是MKAnnotation協議要求實現的方法。
MapLocation.m
#pragma mark - - (void)dealloc { [streetAddress release]; [city release]; [state release]; [zip release]; [super dealloc]; } #pragma mark - #pragma mark NSCoding Methods - (void) encodeWithCoder: (NSCoder *)encoder { [encoder encodeObject: [self streetAddress] forKey: @"streetAddress"]; [encoder encodeObject: [self city] forKey: @"city"]; [encoder encodeObject: [self state] forKey: @"state"]; [encoder encodeObject: [self zip] forKey: @"zip"]; } - (id) initWithCoder: (NSCoder *)decoder { if (self = [super init]) { [self setStreetAddress: [decoder decodeObjectForKey: @"streetAddress"]]; [self setCity: [decoder decodeObjectForKey: @"city"]]; [self setState: [decoder decodeObjectForKey: @"state"]]; [self setZip: [decoder decodeObjectForKey: @"zip"]]; } return self; }
encodeWithCoder:和initWithCoder:是NSCoding協議要求實現方法。
11.3 Web地圖
在iOS中我們還可以使用Web地圖。
- (IBAction)webMap:(id)sender { CLLocation *lastLocation = [locationManager location]; if(!lastLocation) { UIAlertView *alert; alert = [[UIAlertView alloc] initWithTitle:@"系統錯誤" message:@"還沒有接收到數據!" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil]; [alert show]; [alert release]; return; } NSString *urlString = [NSString stringWithFormat: @"http://maps.google.com/maps?q=Here+I+Am!@%f,%f", lastLocation.coordinate.latitude, lastLocation.coordinate.longitude]; NSURL *url = [NSURL URLWithString:urlString]; [[UIApplication sharedApplication] openURL:url]; }
http://maps.google.com/maps?q=Here+I+Am!@%f,%f是請求Web地圖的網站,q后面上參數。
[[UIApplication sharedApplication] openURL:url];打開iOS內置的瀏覽器,即在內置瀏覽器中打開地圖。
注:
1 本教程是基於關東升老師的教程
2 基於黑蘋果10.6.8和xcode4.2
3 本人初學,有什么不對的望指教
4 教程會隨着本人學習,持續更新
5 教程是本人從word筆記中拷貝出來了,所以格式請見諒





