平時在寫項目的時候可能會遇到需要使用定位服務的地方,比如說獲取位置和導航等。因此這里我會使用OC自帶的庫以及蘋果系統的地圖來獲取定位以及顯示在地圖上。
開始前的設置
在獲取定位前,需要在項目文件的info中添加兩個關鍵字,用于向用戶請求定位服務。在請求定位服務的彈窗中會顯示我們添加的字段
<key>Privacy - Location When In Use Usage Description
<value>使用程序的時候獲取本機位置<key>Privacy - Location Always Usage Description
<value>總是獲取本機位置
運行效果:
獲取當前位置的經緯度
- 在寫代碼前需要添加對應的庫以及設置相關的屬性:
#import <UIKit/UIKit.h>
// 關于定位以及地圖的庫
#import <MapKit/MKMapView.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>@interface ViewController : UIViewController<CLLocationManagerDelegate, MKMapViewDelegate>//設置一個定位管理者的屬性
@property (nonatomic, strong) CLLocationManager *locationManager;
//存儲推算出當前的地理位置信息,這個屬性用于獲取當前位置信息推算出的信息,比如有了經緯度而推算出的省、市、區等
@property (nonatomic, strong) CLGeocoder *geoCoder;//定義屬性獲取存儲到的位置信息
@property (nonatomic, retain) CLLocation *myLocation;//MKMapView是iOS中MapKit框架中的一個類,用于顯示地圖,并提供與地圖相關的交互功能
@property (nonatomic, strong) MKMapView *mapView;@end
- 開始定位:
//開始定位
- (void)dingWei {self.locationManager = [[CLLocationManager alloc] init];//desiredAccuracy用于指定定位服務精度, kCLLocationAccuracyBest表示最高精度,這個設置的優勢是提供了最準確的位置信息,但代價是更高的能耗。其他定位精度設置,例如 kCLLocationAccuracyNearestTenMeters 或 kCLLocationAccuracyHundredMeters,它們提供了較低的精度但更節能。self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;//distanceFilter 屬性用于設置設備移動的距離,當設備移動超過這個距離時,會觸發位置更新。distanceFilter 被設置為 10.0 米。這意味著只有當設備移動超過 10.0 米時,才會觸發新的位置更新。self.locationManager.distanceFilter = 10.0f;//檢查設備的系統版本是否可以進行定位if ([CLLocationManager locationServicesEnabled]) {self.locationManager.delegate = self;//如果是,則調用 requestWhenInUseAuthorization 方法請求用戶在應用處于前臺時獲取位置信息的授權。dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[self.locationManager requestWhenInUseAuthorization];});self.geoCoder = [[CLGeocoder alloc] init];} else {NSLog(@"ERROR");}
}
CLLocationManager其相關的屬性:
desiredAccuracy位置的精度屬性,取值有如下幾種:
kCLLocationAccuracyBest:精確度最佳
kCLLocationAccuracynearestTenMeters:精確度10m以內
kCLLocationAccuracyHundredMeters:精確度100m以內
kCLLocationAccuracyKilometer:精確度1000m以內
kCLLocationAccuracyThree:精確度3000m以內
- 在代理方法中獲取需要的位置信息
//在代理方法中獲取需要的位置信息
//下面的方法中,locations是一個數組類型,其最后一個元素就是我們的經緯度坐標,類型為CLLocation,如果想將它設置為屬性,修飾符一定要是retain
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {NSLog(@"%lu", locations.count);self.myLocation = locations.lastObject;NSLog(@"經度: %f, 緯度: %f", self.myLocation.coordinate.longitude, self.myLocation.coordinate.latitude);// 獲取到位置后再進行反地理編碼[self reverseGeocodeLocation:self.myLocation];
}- (void)reverseGeocodeLocation:(CLLocation *)location {[self.geoCoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {if (placemarks.count > 0) {CLPlacemark *placemark = [placemarks objectAtIndex:0];NSLog(@"%@", placemark.name);NSString *city = placemark.locality;if (!city) {city = placemark.administrativeArea;}NSLog(@"位置名:%@", placemark.name);NSLog(@"街道:%@", placemark.thoroughfare);NSLog(@"子街道:%@", placemark.subThoroughfare);NSLog(@"市:%@", placemark.locality);NSLog(@"區:%@", placemark.subLocality);NSLog(@"國家:%@", placemark.country);// 在這里調用顯示地圖的方法[self showLocationOnMapWithLatitude:location.coordinate.latitude longitude:location.coordinate.longitude];}}];
}
- 改變定位權限
// 在此回調中處理定位權限的改變
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager {CLAuthorizationStatus status = manager.authorizationStatus;dispatch_async(dispatch_get_main_queue(), ^{if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways) {// 在這里執行需要權限的操作,例如啟動定位服務//設置允許在應用在后臺運行時繼續獲取位置更新self.locationManager.allowsBackgroundLocationUpdates = NO;//開始獲取設備的當前位置信息[self.locationManager startUpdatingLocation];self.geoCoder = [[CLGeocoder alloc] init];[self jiSuanDistance];self.mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];self.mapView.delegate = self;[self.view addSubview:self.mapView];} else {NSLog(@"ERROR");}});
}
- 獲取定位出錯時調用如下方法:
//獲取位置出錯的時候調用下面的協議方法
- (void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {if (error) {NSLog(@"ERROR");}
}
運行結果:
測算兩個經緯度之間的距離
//測算兩個經緯度坐標之間的距離
- (void) jiSuanDistance {CLLocation *before = [[CLLocation alloc] initWithLatitude:11.111 longitude:222.222];CLLocationDistance meters = [self.myLocation distanceFromLocation:before];NSLog(@"相距: %f米", meters);
}
運行結果:
將位置定位在地圖上
這里使用的是蘋果自帶的地圖
- (void)showLocationOnMapWithLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude {//創建坐標點CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);//以指定的坐標為中心,設置地圖顯示范圍。這里的參數 1000 表示地圖的緯度和經度跨度都為 1000 米。MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coordinate, 1000, 1000);//調整地圖顯示區域,region 是一個 MKCoordinateRegion 結構體,表示地圖的中心點和跨度,這里 region 代表指定的坐標點為中心[self.mapView setRegion:region animated:YES];// 添加標注//MKPointAnnotation是 MapKit 框架中的一部分,用于表示地圖上的點標注MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];//將coordinate屬性設置為當前經緯度坐標annotation.coordinate = coordinate;//為地圖添加標記[self.mapView addAnnotation:annotation];
}
運行結果: