平时在写项目的时候可能会遇到需要使用定位服务的地方,比如说获取位置和导航等。因此这里我会使用OC自带的库以及苹果系统的地图来获取定位以及显示在地图上。
开始前的设置
在获取定位前,需要在项目文件的info中添加两个关键字,用于向用户请求定位服务。在请求定位服务的弹窗中会显示我们添加的字段
<key>Privacy - Location When In Use Usage Description
<value>使用程序的时候获取本机位置
<key>Privacy - Location Always Usage Description
<value>总是获取本机位置
运行效果:
获取当前位置的经纬度
- 在写代码前需要添加对应的库以及设置相关的属性:
objectivec
#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
- 开始定位:
objectivec
//开始定位
- (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以内
- 在代理方法中获取需要的位置信息
objectivec
//在代理方法中获取需要的位置信息
//下面的方法中,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];
}
}];
}
- 改变定位权限
objectivec
// 在此回调中处理定位权限的改变
- (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");
}
});
}
- 获取定位出错时调用如下方法:
objectivec
//获取位置出错的时候调用下面的协议方法
- (void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if (error) {
NSLog(@"ERROR");
}
}
运行结果:
测算两个经纬度之间的距离
objectivec
//测算两个经纬度坐标之间的距离
- (void) jiSuanDistance {
CLLocation *before = [[CLLocation alloc] initWithLatitude:11.111 longitude:222.222];
CLLocationDistance meters = [self.myLocation distanceFromLocation:before];
NSLog(@"相距: %f米", meters);
}
运行结果:
将位置定位在地图上
这里使用的是苹果自带的地图
objectivec
- (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];
}
运行结果: