前言:
最近做的项目需要通过定位来获取当前所在位置的县一级的地名,由于没有用到地图,就选择iOS自带框架CoreLocation来实现。期间也有遇到一些问题,这里也会和大家分享,以后如果有人遇到同样的问题就可以解决了。
CoreLocation介绍
在iOS中通过Core Location框架进行定位操作。Core Location自身可以单独使用,和地图开发框架MapKit完全是独立的。在CoreLocation中主要包含了定位、地理编码(包括反编码)功能。
使用CoreLoaction中CLLocationManager类实现定位功能,首先看一下这个类的一些主要方法和属性:
+ (BOOL)locationServicesEnabled; | 是否启用定位服务 |
+ (CLAuthorizationStatus)authorizationStatus; | 定位服务授权状态,返回枚举类型: |
desiredAccuracy | 定位精度,枚举类型: |
distanceFilter | 位置信息更新最小距离, 只有移动大于这个距离 才更新位置信息,默认 为kCLDistanceFilterNone: 不进行距离限制 |
startUpdatingLocation | 开始定位追踪,开始定位后将按照用户设置的更新频率执行-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;方法反馈定位信息 |
stopUpdatingLocation | 停止定位追踪 |
startUpdatingHeading | 开始导航方向追踪 |
stopUpdatingHeading | 停止导航方向追踪 |
startMonitoringForRegion: | 开始对某个区域进行定位追踪,开始对某个区域进行定位后。如果用户进入或者走出某个区域会调用- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region和- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region代理方法反馈相关信息 |
stopMonitoringForRegion: | 停止对某个区域进行定位追踪 |
requestWhenInUseAuthorization | 请求获得应用使用时的定位服务授权,注意使用此方法前在要在info.plist中配置NSLocationWhenInUseUsageDescription |
requestAlwaysAuthorization | 请求获得应用一直使用定位服务授权,注意使用此方法前要在info.plist中配置NSLocationAlwaysUsageDescription |
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations; | 位置发生改变后执行(第一次定位到某个位置之后也会执行 |
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading | 导航方向发生变化后执行 |
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region | 进入某个区域之后执行 |
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region | 走出某个区域之后执行 |
地理编码
除了提供位置跟踪功能之外,在定位服务中还包含CLGeocoder类用于处理地理编码和逆地理编码。
地理编码:根据地名确定坐标 - (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
逆地理编码:根据坐标确定地名 - (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
使用步骤
1.引入#import <CoreLocation/CoreLocation.h> 并创建定位管理对象self.locationManager = [[CLLocationManager alloc]init]; 和地理编码对象self.geocoder = [[CLGeocoder alloc]init];
2.遵循协议CLLocationManagerDelegate,设置代理
3.实现代理方法-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations获取经纬度再由逆地理编码获取地名。
遇到的问题
刚才上边说道在这期间遇到了问题,就是遵循协议,设置代理之后实现协议方法,还是不能定位,后来发现要在info.plist文件做一些配置NSLocationWhenInUseUsageDescription(前台) 、 NSLocationAlwaysUsageDescription (后台)两个均为Boolean类型值为YES,
代码:
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
@interface ViewController ()<CLLocationManagerDelegate>
@property(nonatomic,strong)CLLocationManager *locationManager;
@property(nonatomic,strong)CLGeocoder *geocoder;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//初始化定位管理器
self.locationManager = [[CLLocationManager alloc]init];
if (![CLLocationManager locationServicesEnabled]) {
NSLog(@"定位服务可能未打开");
return;
}
[_locationManager startUpdatingLocation];
//如果没有授权就请求用户授权
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
[_locationManager requestWhenInUseAuthorization];
}else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse){
//设置代理
_locationManager.delegate = self;
//设置精确度
_locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
//定位频率,每隔多少米定位一次
CLLocationDistance distance = 10.0; // 十米一次
_locationManager.distanceFilter = distance;
//启动跟踪定位
[_locationManager startUpdatingLocation];
}
//地理编码:根据地名获取坐标
self.geocoder = [[CLGeocoder alloc]init];
[self getCoordinateByAddress:@"威县"];
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark -- 代理方法
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
//取出数组第一个位置
CLLocation *location = [locations firstObject];
CLLocationCoordinate2D coordinate = location.coordinate;
NSLog(@"经度 = %f,纬度 = %f ",coordinate.longitude,coordinate.latitude);
[self getAddressByLatitude:coordinate.latitude longitude:coordinate.longitude];
}
#pragma mark -- 地理编码(根据地名确定坐标)
-(void)getCoordinateByAddress:(NSString *)address{
[self.geocoder geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
CLPlacemark *placemark = [placemarks firstObject];
//位置
CLLocation *location = placemark.location;
//区域
CLRegion *region = placemark.region;
//详细信息
NSDictionary *addressDic = placemark.addressDictionary;
// NSLog(@"location = %@,region = %@,dict =%@",location,region,addressDic);
}];
}
#pragma mark -- 逆地理编码 (根据坐标取得地名)
-(void)getAddressByLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude{
CLLocation *location = [[CLLocation alloc]initWithLatitude:latitude longitude:longitude];
[self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
CLPlacemark *placemark = placemarks.firstObject;
NSLog(@"%@,%@",placemark.locality , placemark.subLocality);
}];
}