在移动互联网时代,移动app能解决用户的很多生活琐事,比如
周边:找餐馆、找KTV、找电影院等等
导航:根据用户设定的起点和终点,进行路线规划,并指引用户如何到达
在上述应用中,都用到了定位和地图功能,在iOS开发中,要想加入这2大功能,必须基于2个框架进行开发
CoreLocation :用于地理定位,地理编码,区域监听等(着重功能实现)
MapKit :用于地图展示,例如大头针,路线、覆盖层展示等(着重界面展示)
2个热门专业术语
LBS :Location Based Service
SoLoMo :Social Local Mobile(索罗门)
CoreLocation框架的使用
CoreLocation框架使用前提
导入框架(Xcode5.0之后可以省略)
导入主头文件
#import
CoreLocation框架使用须知
CoreLocation框架中所有数据类型的前缀都是CL
CoreLocation中使用CLLocationManager对象来做用户定位
CLLocationManager
CLLocationManager的常用操作
开始更新用户位置
- (void)startUpdatingLocation;
停止更新用户位置
- (void) stopUpdatingLocation;
当调用了startUpdatingLocation方法后,就开始不断地请求、刷新用户的位置,一旦请求到用户位置就会调用代理的下面方法
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
locations参数里面装着CLLocation对象
CLLocationManager补充
为了严谨起见,最好在使用定位功能之前判断当前应用的定位功能是否可用
CLLocationManager有个类方法可以判断当前应用的定位功能是否可用
+ (BOOL)locationServicesEnabled;
@property(assign, nonatomic) CLLocationDistance distanceFilter;
每隔多少米定位一次
@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;
定位精确度(越精确就越耗电)
CLLocation
CLLocation用来表示某个位置的地理信息,比如经纬度、海拔等等
@property(readonly, nonatomic) CLLocationCoordinate2D coordinate;
经纬度
@property(readonly, nonatomic) CLLocationDistance altitude;
海拔
@property(readonly, nonatomic) CLLocationDirection course;
路线,航向(取值范围是0.0° ~ 359.9°,0.0°代表真北方向)
@property(readonly, nonatomic) CLLocationSpeed speed;
移动速度(单位是m/s)
用- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location方法可以计算2个位置之间的距离
用户隐私的保护
从iOS 6开始,苹果在保护用户隐私方面做了很大的加强,以下操作都必须经过用户批准授权
要想获得用户的位置
想访问用户的通讯录、日历、相机、相册等等
当想访问用户的隐私信息时,系统会自动弹出一个对话框让用户授权
用户隐私的保护
开发者可以在Info.plist中设置NSLocationUsageDescription说明定位的目的(Privacy - Location Usage Description)
一旦用户选择了“Don’t Allow”,意味着你的应用以后就无法使用定位功能
为了提高用户的授权概率,段子一定要写好!
iOS8.0+的定位适配
从iOS 8.0开始,苹果进一步加强了对用户隐私的保护。
当APP想访问用户的隐私信息时,系统不再自动弹出一个对话框让用户授权
解决方案:
(1)调用iOS 8.0的API,主动请求用户授权
- (void)requestAlwaysAuthorization // 请求允许在前后台都能获取用户位置的授权
- (void)requestWhenInUseAuthorization // 请求允许在前台获取用户位置的授权
(2)务必在info.plist文件中配置对应的键值, 否则以上请求授权的方法不生效
NSLocationAlwaysUsageDescription : 允许在前后台获取GPS的描述
NSLocationWhenInUseDescription : 允许在前台获取GPS的描述
iOS9.0 定位补充
iOS 9.0 如果当前处于前台授权状态,默认是不可以后台获取用户位置。但可以设置以下属性为YES,就可以继续获取后台位置,但是会出现蓝条
@property(assign, nonatomic) BOOL allowsBackgroundLocationUpdates
使用注意:必须设置对应的后台模式:location updates
iOS 9.0 可以单次请求用户位置
- (void)requestLocation
-(void)locationManager:(nonnull CLLocationManager *)manager didUpdateLocations:(nonnull NSArray *)locations // 成功调用
-(void)locationManager:(nonnull CLLocationManager *)manager didFailWithError:(nonnull NSError *)error // 失败调用
CLLocationCoordinate2D
CLLocationCoordinate2D是一个用来表示经纬度的结构体,定义如下
typedef struct {
CLLocationDegrees latitude; // 纬度
CLLocationDegrees longitude; // 经度
} CLLocationCoordinate2D;
一般用CLLocationCoordinate2DMake函数来创建CLLocationCoordinate2D
本初子午线
穿过英国伦敦格林文治天文台
往东边(右边)走,是东经(E)
往西边(左边)走,是西经(W)
东西经各180°,总共360°
赤道
往北边(上边)走,是北纬(N)
往南边(下边)走,是南纬(S)
南北纬各90°,总共180°
横跨经度\纬度越大(1° ≈ 111km)
表示的范围就越大
在地图上看到的东西就越小
天朝的经纬度范围
纬度范围:N 3°51′ ~ N 53°33′
经度范围:E 73°33′ ~ E 135°05
CLGeocoder
使用CLGeocoder可以完成“地理编码”和“反地理编码”
地理编码:根据给定的地名,获得具体的位置信息(比如经纬度、地址的全称等)
反地理编码:根据给定的经纬度,获得具体的位置信息
地理编码方法
- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
反地理编码方法
- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
CLGeocodeCompletionHandler
当地理\反地理编码完成时,就会调用CLGeocodeCompletionHandler
typedef void (^CLGeocodeCompletionHandler)(NSArray *placemarks, NSError *error);
这个block传递2个参数
error :当编码出错时(比如编码不出具体的信息)有值
placemarks :里面装着CLPlacemark对象
CLPlacemark
CLPlacemark的字面意思是地标,封装详细的地址位置信息
@property (nonatomic, readonly) CLLocation *location;
地理位置
@property (nonatomic, readonly) CLRegion *region;
区域
@property (nonatomic, readonly) NSDictionary *addressDictionary;
详细的地址信息
@property (nonatomic, readonly) NSString *name;
地址名称
@property (nonatomic, readonly) NSString *locality;
城市
iOS8.0以前
手动配置infoPlist文件的key和手动勾选后台模式
或者
手动配置两个infoPlist文件的key
这两个都是一个意思
配置定位获取授权信息
配置后台定位的两种方法
iOS8以前代码:
#import "ViewController.h"
#import
@interface ViewController ()
// 位置管理者
@property (nonatomic, strong) CLLocationManager *locationM;
@end
@implementation ViewController
#pragma mark - 懒加载对象,并在懒加载方法中进行部分初始化操作
/** 懒加载的好处
* 1. 防止对象提前创建,占用内存空间
* 2. 防止使用的时候,还没有被创建
* 3. 防止被重复创建
* 4. 可以在懒加载方法里面进行初始化设置
*/
- (CLLocationManager *)locationM
{
if (!_locationM) {
// 创建位置管理器
_locationM = [[CLLocationManager alloc] init];
// 设置代理
_locationM.delegate = self;
/** ------附加设置------- */
// 设置定位距离过滤参数 (当上次定位和本次定位之间的距离 >= 此值时,才会调用代理通知开发者)
_locationM.distanceFilter = 500;
// 设置定位精度 (精确度越高,越耗电,所以需要我们根据实际情况,设定对应的精度)
_locationM.desiredAccuracy = kCLLocationAccuracyBest;
}
return _locationM;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)touchesBegan:(nonnull NSSet *)touches withEvent:(nullable UIEvent *)event
{
// 2.使用位置管理器进行定位
if([CLLocationManager locationServicesEnabled])
{
[self.locationM startUpdatingLocation];
}else
{
NSLog(@"不能定位呀");
}
}
#pragma mark -CLLocationManagerDelegate
/**
* 当位置管理器,获取到位置后,就会调用这样的方法
*/
-(void)locationManager:(nonnull CLLocationManager *)manager didUpdateLocations:(nonnull NSArray *)locations
{
NSLog(@"已经定位到了!");
// 定位到之后,可以调用此方法停止更新位置
[self.locationM stopUpdatingLocation];
}
@end
iOS8.0以后有两种方式:这两种方式都需要请求授权
第一种:infoPlist文件配置key(前台) + 手动配置勾选后台
第一种方式相当于在infoPlist文件中配置了两个key
第二种:infoPlist文件配置key(前后台)
第二种方式只需要在infoPlist文件中配置了一个key
区别:第一种进入后台手机上方会有蓝条,第二种进入后台没有蓝条。
iOS8.0和iOS8.0以后
配置:
#import "ViewController.h"
#import
@interface ViewController ()
// 位置管理者
@property (nonatomic, strong) CLLocationManager *locationM;
@end
@implementation ViewController
#pragma mark - 懒加载对象,并在懒加载方法中进行部分初始化操作
- (CLLocationManager *)locationM
{
if (!_locationM) {
// 创建位置管理器
_locationM = [[CLLocationManager alloc] init];
// 设置代理
_locationM.delegate = self;
/** ------附加设置------- */
// 设置定位距离过滤参数 (当上次定位和本次定位之间的距离 >= 此值时,才会调用代理通知开发者)
// _locationM.distanceFilter = 500;
// 设置定位精度 (精确度越高,越耗电,所以需要我们根据实际情况,设定对应的精度)
_locationM.desiredAccuracy = kCLLocationAccuracyBest;
/** ------适配iOS8.0------- */
// 判断系统版本
if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
/**
* 注意:如果两个授权都请求,那么先执行前面那个请求弹框,后面那个请求授权 有可能 下次被调用时,才会起作用
* 如果,先请求的是“前后台授权”,那“前台授权”即使被调用,也不会有反应(因为“前后台授权”权限大于“前台授权”)
* 反之,如果先请求的是“前台授权”,而且用户选中的是“允许”,那下次被调用时“前后台授权”会做出请求,但只请求一次
*
* 本质:1. 两个授权同时请求,先执行前面那个授权请求
* 2. “前后台请求授权”方法,在(当前的授权状态 == 用户未选择状态 / 前台授权状态) 才会起作用
* 3. “前台请求授权”方法,在(当前的授权状态 == 用户未选择状态) 才会起作用
*/
// 请求前台的授权(默认当App进入前台后可以定位,后台不可定位)
// 当后台模式添加location后,即使后台也可以获取用户位置,但会出现蓝条
// [_locationM requestWhenInUseAuthorization];
// 请求前后台的授权(前后台都可以获取用户位置,而且不会出现蓝条)
[_locationM requestAlwaysAuthorization];
}
// 另外一种适配不同版本API的方法
// if ([_locationM respondsToSelector:@selector(requestAlwaysAuthorization)]) {
//
// [_locationM requestAlwaysAuthorization];
// [_locationM requestWhenInUseAuthorization];
// }
}
return _locationM;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)touchesBegan:(nonnull NSSet *)touches withEvent:(nullable UIEvent *)event
{
// 2.使用位置管理器进行定位
if([CLLocationManager locationServicesEnabled])
{
[self.locationM startUpdatingLocation];
}else
{
NSLog(@"不能定位呀");
}
}
#pragma mark -CLLocationManagerDelegate
/**
* 当用户授权状态发生变化时调用
*/
-(void)locationManager:(nonnull CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status) {
// 用户还未决定
case kCLAuthorizationStatusNotDetermined:
{
NSLog(@"用户还未决定");
break;
}
// 问受限
case kCLAuthorizationStatusRestricted:
{
NSLog(@"访问受限");
break;
}
// 定位关闭时和对此APP授权为never时调用
case kCLAuthorizationStatusDenied:
{
// 定位是否可用(是否支持定位或者定位是否开启)
if([CLLocationManager locationServicesEnabled])
{
NSLog(@"定位开启,但被拒");
}else
{
NSLog(@"定位关闭,不可用");
}
break;
}
// 获取前后台定位授权
case kCLAuthorizationStatusAuthorizedAlways:
// case kCLAuthorizationStatusAuthorized: // 失效,不建议使用
{
NSLog(@"获取前后台定位授权");
break;
}
// 获得前台定位授权
case kCLAuthorizationStatusAuthorizedWhenInUse:
{
NSLog(@"获得前台定位授权");
break;
}
default:
break;
}
}
/**
* 当位置管理器,获取到位置后,就会调用这样的方法
*/
-(void)locationManager:(nonnull CLLocationManager *)manager didUpdateLocations:(nonnull NSArray *)locations
{
NSLog(@"已经定位到了!");
}
@end
iOS9之后
配置:
需要在iOS8的第一种方法上添加一行代码
// 位置管理器
@property (nonatomic, strong) CLLocationManager *locationM;
self.locationM.allowsBackgroundLocationUpdates = YES;
infoPlist文件配置key(前台) + 手动配置勾选后台
相当于在infoPlist文件中配置了两个key
并且比iOS8多了一个方法,
[self.locationM requestLocation];
能自定提高定位的精确度,因为定位精度越小,越耗时,系统会一步一步提高精度,当系统发现超时,就会将此时(或者说上次的定位值)返回给你。
而且,代理还要实现定时失败的方法。
还要注意requestLocation不能和一些方法同用,请看系统注释。
代码:
#import "ViewController.h"
#import
@interface ViewController ()
// 位置管理器
@property (nonatomic, strong) CLLocationManager *locationM;
@end
@implementation ViewController
#pragma mark - 懒加载对象,并在懒加载方法中进行部分初始化操作
- (CLLocationManager *)locationM
{
if (!_locationM) {
// 创建位置管理器
_locationM = [[CLLocationManager alloc] init];
// 设置代理
_locationM.delegate = self;
// 判断系统版本,请求前台授权
if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
// 在iOS9.0+(如果当前授权状态是使用时授权,那么App退到后台后,将不能获取用户位置,即使勾选后台模式:location)
[_locationM requestWhenInUseAuthorization];
}
// 要想继续获取位置,需要使用以下属性进行设置(注意勾选后台模式:location)但会出现蓝条
if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
_locationM.allowsBackgroundLocationUpdates = YES;
}
}
return _locationM;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)touchesBegan:(nonnull NSSet *)touches withEvent:(nullable UIEvent *)event
{
// 2.使用位置管理器进行定位
if([CLLocationManager locationServicesEnabled])
{
// [self.locationM startUpdatingLocation];
// 作用:按照定位精确度从低到高进行排序,逐个进行定位。如果获取到的位置不是精确度最高的那个,也会在定位超时后,通过代理告诉外界
// 注意:一个要实现代理的定位失败方法; 二:不能与startUpdatingLocation同时使用
[self.locationM requestLocation];
}else
{
NSLog(@"不能定位呀");
}
}
#pragma mark -CLLocationManagerDelegate
/**
* 当用户授权状态发生变化时调用
*/
-(void)locationManager:(nonnull CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status) {
// 用户还未决定
case kCLAuthorizationStatusNotDetermined:
{
NSLog(@"用户还未决定");
break;
}
// 问受限
case kCLAuthorizationStatusRestricted:
{
NSLog(@"访问受限");
break;
}
// 定位关闭时和对此APP授权为never时调用
case kCLAuthorizationStatusDenied:
{
// 定位是否可用(是否支持定位或者定位是否开启)
if([CLLocationManager locationServicesEnabled])
{
NSLog(@"定位开启,但被拒");
}else
{
NSLog(@"定位关闭,不可用");
}
break;
}
// 获取前后台定位授权
case kCLAuthorizationStatusAuthorizedAlways:
// case kCLAuthorizationStatusAuthorized: // 失效,不建议使用
{
NSLog(@"获取前后台定位授权");
break;
}
// 获得前台定位授权
case kCLAuthorizationStatusAuthorizedWhenInUse:
{
NSLog(@"获得前台定位授权");
break;
}
default:
break;
}
}
/**
* 当位置管理器,获取到位置后,就会调用这样的方法
*/
-(void)locationManager:(nonnull CLLocationManager *)manager didUpdateLocations:(nonnull NSArray *)locations
{
NSLog(@"已经定位到了!--%@", locations);
}
/**
* 当定位失败后调用此方法
*/
-(void)locationManager:(nonnull CLLocationManager *)manager didFailWithError:(nonnull NSError *)error
{
NSLog(@"定位失败--%@", error.localizedDescription);
}
@end
CoreLocation框架的基本实现
在9.0上修改
#import "ViewController.h"
#import
@interface ViewController ()
// 位置管理者
@property (nonatomic, strong) CLLocationManager *locationM;
@end
@implementation ViewController
#pragma mark - 懒加载对象,并在懒加载方法中进行部分初始化操作
- (CLLocationManager *)locationM
{
if (!_locationM) {
// 创建位置管理器
_locationM = [[CLLocationManager alloc] init];
// 设置代理
_locationM.delegate = self;
// 判断系统版本,请求前后台授权
if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
[_locationM requestAlwaysAuthorization];
}
// iOS9.0 以前,使用后台定位没有提示,从iOS9.0开始, 如果使用后台定位没有调用此API,屏幕会出现蓝条(类似热点开启)
// 注意设置对应的后台运行模式,否则会崩溃
if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
_locationM.allowsBackgroundLocationUpdates = YES;
}
}
return _locationM;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)touchesBegan:(nonnull NSSet *)touches withEvent:(nullable UIEvent *)event
{
// 2.使用位置管理器进行定位
if([CLLocationManager locationServicesEnabled])
{
// [self.locationM startUpdatingLocation];
// 只请求一次定位位置(注意:必须实现代理的-locationManager:didFailWithError:方法)
// 不能与startUpdatingLocation方法同时使用
[self.locationM requestLocation];
}else
{
NSLog(@"不能定位呀");
}
}
#pragma mark -CLLocationManagerDelegate
/**
* 当用户授权状态发生变化时调用
*/
-(void)locationManager:(nonnull CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status) {
// 用户还未决定
case kCLAuthorizationStatusNotDetermined:
{
NSLog(@"用户还未决定");
break;
}
// 问受限
case kCLAuthorizationStatusRestricted:
{
NSLog(@"访问受限");
break;
}
// 定位关闭时和对此APP授权为never时调用
case kCLAuthorizationStatusDenied:
{
// 定位是否可用(是否支持定位或者定位是否开启)
if([CLLocationManager locationServicesEnabled])
{
NSLog(@"定位开启,但被拒");
}else
{
NSLog(@"定位关闭,不可用");
}
break;
}
// 获取前后台定位授权
case kCLAuthorizationStatusAuthorizedAlways:
// case kCLAuthorizationStatusAuthorized: // 失效,不建议使用
{
NSLog(@"获取前后台定位授权");
break;
}
// 获得前台定位授权
case kCLAuthorizationStatusAuthorizedWhenInUse:
{
NSLog(@"获得前台定位授权");
break;
}
default:
break;
}
}
/**
* 当位置管理器,获取到位置后,就会调用这样的方法
*/
-(void)locationManager:(nonnull CLLocationManager *)manager didUpdateLocations:(nonnull NSArray *)locations
{
CLLocation *location = [locations firstObject];
NSLog(@"%@", location);
}
/**
* 当定位失败后调用此方法
*/
-(void)locationManager:(nonnull CLLocationManager *)manager didFailWithError:(nonnull NSError *)error
{
NSLog(@"定位失败--%@", error.localizedDescription);
}
@end
指南针
#import "ViewController.h"
#import
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *compassView;
@property (nonatomic, strong) CLLocationManager *locationM;
@end
@implementation ViewController
#pragma mark - 懒加载
-(CLLocationManager *)locationM
{
if (!_locationM) {
/**
* 注意:获取手机设备朝向,不需要用户授权
*/
_locationM = [[CLLocationManager alloc] init];
_locationM.delegate = self;
}
return _locationM;
}
- (void)viewDidLoad {
[super viewDidLoad];
if ([CLLocationManager headingAvailable]) {
// 开始监听设备朝向
[self.locationM startUpdatingHeading];
}
}
#pragma mark - CLLocationManagerDelegate
-(void)locationManager:(nonnull CLLocationManager *)manager didUpdateHeading:(nonnull CLHeading *)newHeading
{
// 获取当前设备朝向(磁北方向)
CGFloat angle = newHeading.magneticHeading;
// 转换成为弧度
CGFloat radian = angle / 180.0 * M_PI;
// 反向旋转指南针
[UIView animateWithDuration:0.5 animations:^{
self.compassView.transform = CGAffineTransformMakeRotation(-radian);
}];
}
@end
区域监听
#import "ViewController.h"
#import
@interface ViewController ()
@property (nonatomic, strong) CLLocationManager *locationM;
@end
@implementation ViewController
#pragma mark - 懒加载
-(CLLocationManager *)locationM
{
if (!_locationM) {
_locationM = [[CLLocationManager alloc] init];
_locationM.delegate = self;
if ([_locationM respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[_locationM requestAlwaysAuthorization];
}
}
return _locationM;
}
- (void)viewDidLoad {
[super viewDidLoad];
// 创建区域中心
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(29.12345, 131.23456);
// 创建区域(指定区域中心,和区域半径)
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:1000 identifier:@"家里"];
// 开始监听指定区域
[self.locationM startMonitoringForRegion:region];
}
#pragma mark - CLLocationManagerDelegate
// 进去监听区域后调用(调用一次)
-(void)locationManager:(nonnull CLLocationManager *)manager didEnterRegion:(nonnull CLRegion *)region
{
NSLog(@"进入区域---%@", region.identifier);
[manager stopMonitoringForRegion:region];
}
// 离开监听区域后调用(调用一次)
-(void)locationManager:(nonnull CLLocationManager *)manager didExitRegion:(nonnull CLRegion *)region
{
NSLog(@"离开区域---%@", region.identifier);
}
@end
地理编码
#import "ViewController.h"
#import
#import
@interface ViewController ()
// 地址详情TextView
@property (weak, nonatomic) IBOutlet UITextView *addressDetailTV;
// 纬度TextField
@property (weak, nonatomic) IBOutlet UITextField *latitudeTF;
// 经度度TextField
@property (weak, nonatomic) IBOutlet UITextField *longtitudeTF;
// 用作地理编码、反地理编码的工具类
@property (nonatomic, strong) CLGeocoder *geoC;
@end
@implementation ViewController
#pragma mark - 懒加载
-(CLGeocoder *)geoC
{
if (!_geoC) {
_geoC = [[CLGeocoder alloc] init];
}
return _geoC;
}
// 地理编码
- (IBAction)geoCoder {
if ([self.addressDetailTV.text length] == 0) {
return;
}
// 地理编码方案一:直接根据地址进行地理编码(返回结果可能有多个,因为一个地点有重名)
[self.geoC geocodeAddressString:self.addressDetailTV.text completionHandler:^(NSArray * __nullable placemarks, NSError * __nullable error) {
// 包含区,街道等信息的地标对象
CLPlacemark *placemark = [placemarks firstObject];
// 城市名称
// NSString *city = placemark.locality;
// 街道名称
// NSString *street = placemark.thoroughfare;
// 全称
NSString *name = placemark.name;
self.addressDetailTV.text = [NSString stringWithFormat:@"%@", name];
self.latitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.latitude];
self.longtitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.longitude];
}];
// 地理编码方案二:根据地址和区域两个条件进行地理编码(更加精确)
// [self.geoC geocodeAddressString:self.addressDetailTV.text inRegion:nil completionHandler:^(NSArray * __nullable placemarks, NSError * __nullable error) {
// // 包含区,街道等信息的地标对象
// CLPlacemark *placemark = [placemarks firstObject];
// self.addressDetailTV.text = placemark.description;
// self.latitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.latitude];
// self.longtitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.longitude];
// }];
// 地理编码方案三:
// NSDictionary *addressDic = @{
// (__bridge NSString *)kABPersonAddressCityKey : @"北京",
// (__bridge NSString *)kABPersonAddressStreetKey : @"棠下街"
// };
// [self.geoC geocodeAddressDictionary:addressDic completionHandler:^(NSArray * __nullable placemarks, NSError * __nullable error) {
// CLPlacemark *placemark = [placemarks firstObject];
// self.addressDetailTV.text = placemark.description;
// self.latitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.latitude];
// self.longtitudeTF.text = [NSString stringWithFormat:@"%f", placemark.location.coordinate.longitude];
// }];
}
// 反地理编码
- (IBAction)decode {
// 过滤空数据
if ([self.latitudeTF.text length] == 0 || [self.longtitudeTF.text length] == 0) {
return;
}
// 创建CLLocation对象
CLLocation *location = [[CLLocation alloc] initWithLatitude:[self.latitudeTF.text doubleValue] longitude:[self.longtitudeTF.text doubleValue]];
// 根据CLLocation对象进行反地理编码
[self.geoC reverseGeocodeLocation:location completionHandler:^(NSArray * __nullable placemarks, NSError * __nullable error) {
// 包含区,街道等信息的地标对象
CLPlacemark *placemark = [placemarks firstObject];
// 城市名称
// NSString *city = placemark.locality;
// 街道名称
// NSString *street = placemark.thoroughfare;
// 全称
NSString *name = placemark.name;
self.addressDetailTV.text = [NSString stringWithFormat:@"%@", name];
}];
}
@end