001-地图&定位
一、简介
在iOS开发中,系统提供了两个框架,用来做地图和定位功能
CoreLocation:用于地理定位
Map Kit:用于地图展示
二、CoreLocation框架
1.CoreLocation的使用步骤
1)导入CoreLocation框架(Xcode5之后可以不用导)

2)导入头文件
#import <CoreLocation/CoreLocation.h>
2.CoreLocation框架的使用须知
1)CoreLocation框架中所有数据类型的前缀都是CL
2)CoreLocation中使用CLLocationManager对象来做用户定位
3.模拟器模拟定位功能


4.CoreLocation的定位服务
1)CLLocationManager(定位管理者)
a.获取定位信息 --- iOS8要求手动请求用户授权
①开始定位:- (void)startUpdatingLocation;
②停止定位:- (void)stopUpdatingLocation;
③开始定位,频繁调用协议方法
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
④参数设置
I.设置每个多少米定位一次(单位:米)
属性:@property(assign, nonatomic) CLLocationDistance distanceFilter;
// kCLLocationAccuracyBestForNavigation 最佳导航
// kCLLocationAccuracyBest 最精准
// kCLLocationAccuracyNearestTenMeters 10米
// kCLLocationAccuracyHundredMeters 百米
// kCLLocationAccuracyKilometer 千米
// kCLLocationAccuracyThreeKilometers 3千米
II.定位精准度(越精准越耗电)
属性:@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;
b.获取地理方向 --- 无需手动请求用户授权
①开始获取方向:- (void)startUpdatingHeading;
②停止获取方向:- (void)stopUpdatingHeading;
③开始获取,频繁调用协议方法
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading;
c.检测用户区域 --- iOS8要求手动请求用户授权
①开始检测:- (void)startMonitoringForRegion:(CLRegion *)region;
②停止检测:- (void)stopMonitoringForRegion:(CLRegion *)region;
③开始检测,频繁调用协议方法
I.指定区域内:
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region;
II.指定区域外:
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region;
④区域类(CLRegion)提供的两个子类
I.地图圆形区域类:CLCircularRegion
II.蓝牙信号区域类:CLBeaconRegion
2)CLLocation(位置的地理信息)
CLLocation是用来表示某个位置的地理信息。比如:经纬度、海拔等等
a.经纬度(longitude:经度 latitude:纬度)
属性:@property(readonly, nonatomic) CLLocationCoordinate2D coordinate;
b.海拔高度(单位:米)
属性:@property(readonly, nonatomic) CLLocationDistance altitude;
c.航向(取值范围:0.0° ~ 359.9° 0.0°:真北方向)
属性:@property(readonly, nonatomic) CLLocationDirection course;
d.设备移动的速度(单位:m/s)
属性:@property(readonly, nonatomic) CLLocationSpeed speed;
e.水平精准度
属性:@property(readonly, nonatomic) CLLocationAccuracy horizontalAccuracy;
f.垂直精准度
属性:@property(readonly, nonatomic) CLLocationAccuracy verticalAccuracy;
g.定位返回来的时间戳
属性:@property(readonly, nonatomic, copy) NSDate *timestamp;
h.计算两个位置之间的距离(CLLocationDistance:double类型)
方法:- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location;
3)App定位功能的用户授权(对于iOS8,一些获取用户隐私的功能是需要请求用户授权)
a.在iOS7中只要开始定位,系统自动弹出用户授权框;iOS8以后,苹果公司为保护用户隐私,一些功能需要用户手动授权
b.授权有允许和不允许两情况,安全起见,定位前务必判断用户定位功能是否可用。方法:+ (BOOL)locationServicesEnabled;
c.手动授权方法(只有iOS8以后才有的方法)
①方法1:- (void)requestAlwaysAuthorization; // 无论前台后台均有定位权限
②方法2:- (void)requestWhenInUseAuthorization; // 前台定位权限
d.除方法外,还需要我们在info.plist文件中去配置一些信息
①对应方法1:添加字段NSLocationAlwaysUsageDescription,并说明定位目的
②对应方法2:添加字段NSLocationWhenInUseDescription,并说明定位目的

e.现在最新出来的iOS9在定位授权方面有一个新特性:
@property(assign, nonatomic) BOOL allowsBackgroundLocationUpdates;
iOS9中一个项目可以存在多个定位,我们可以随时更改某一个CLLocationManager的后台定位功能
这里如果我们需要随时改变后台定位授权的状态,除了设置allowsBackgroundLocationUpdates属性为NO,还需要配置info.plist文件:

如果不按照上面plist文件去配置,在后续只要是出现动态更改后台授权的代码,程序必定会崩溃
实例一:获取用户的定位信息
1 // ViewController.h文件 2 #import "ViewController.h" 3 #import <CoreLocation/CoreLocation.h> // 导入头文件 4 5 #pragma mark - 遵循定位协议<CLLocationManagerDelegate> 6 @interface ViewController ()<CLLocationManagerDelegate> 7 8 #pragma mark - CLLocationManager管理者对象 9 @property (nonatomic, strong) CLLocationManager *manager; 10 11 @end 12 13 @implementation ViewController 14 15 #pragma mark - 懒加载 16 // 初始化创建CoreLocation管理者 17 - (CLLocationManager *)manager 18 { 19 if (_manager == nil) { 20 _manager = [[CLLocationManager alloc] init]; 21 } 22 return _manager; 23 } 24 25 - (void)viewDidLoad { 26 [super viewDidLoad]; 27 28 // 设置代理 29 self.manager.delegate = self; 30 31 // 参数设置 32 // a.定位精准度(越精准越耗电) 33 self.manager.desiredAccuracy = kCLLocationAccuracyBest; 34 // b.每隔多少米定位一次(单位:米) 35 // kCLLocationAccuracyBestForNavigation 最佳导航 36 // kCLLocationAccuracyBest 最精准 37 // kCLLocationAccuracyNearestTenMeters 10米 38 // kCLLocationAccuracyHundredMeters 百米 39 // kCLLocationAccuracyKilometer 千米 40 // kCLLocationAccuracyThreeKilometers 3千米 41 self.manager.distanceFilter = 5; 42 43 // iOS8以上:要求手动授权 44 if ([[UIDevice currentDevice] systemVersion].floatValue >= 8.0) { 45 // a.请求前台和后台的定位权限 46 [self.manager requestAlwaysAuthorization]; 47 // b.请求前台的定位权限 48 // [self.manager requestWhenInUseAuthorization]; 49 } else { 50 // 开始定位 51 [self.manager startUpdatingLocation]; 52 } 53 54 // iOS9:同一项目中允许多个定位对象并存,可随时代码控制某个定位对象的后台定位授权 55 if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) { 56 // 后台授权属性:allowsBackgroundLocationUpdates(YES:允许,NO:不允许) 57 self.manager.allowsBackgroundLocationUpdates = YES; 58 } 59 } 60 61 #pragma mark - 协议方法<CLLocationManagerDelegate> 62 // 1.用户授权状态一经改变就会调用 63 - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status 64 { 65 // 授权状态status 66 // kCLAuthorizationStatusNotDetermined 用户还未点击授权框,等待用户授权 67 // kCLAuthorizationStatusRestricted 无法使用定位服务,该状态用户无法改变 68 // kCLAuthorizationStatusDenied 用户拒绝或定位服务总开关关闭 69 // kCLAuthorizationStatusAuthorized 已授权(废弃) 70 // kCLAuthorizationStatusAuthorizedAlways 用户允许该程序无论何时都可授权 71 // kCLAuthorizationStatusAuthorizedWhenInUse 用户同意在程序在可见时授权 72 if (status == kCLAuthorizationStatusNotDetermined) { 73 NSLog(@"等待用户授权"); 74 }else if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) { 75 NSLog(@"授权成功"); 76 77 // 开始定位 78 [self.manager startUpdatingLocation]; 79 } else { 80 NSLog(@"授权失败"); 81 } 82 } 83 // 2.定位成功调用(调用频率非常高,所以要代码控制调用频率) 84 // 参数:locations 位置数组(上一位置、当前位置) 85 - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations 86 { 87 // 1.只需获取一次用户位置信息就停止 88 // [self.manager stopUpdatingLocation]; 89 90 // 2.可以在ViewDidLoad中设置定位精确度和走动范围定位 91 // 用于导航 92 93 // 3.获取最后一次地理位置信息 94 // location.coordinate // 坐标,包含经纬度 95 // location.altitude // 设置海拔高度(单位是米) 96 // location.course // 设置前进方向(0北/90东/180南/270西) 97 // location.horizontalAccuracy // 水平精准度 98 // location.verticalAccuracy // 垂直精准度 99 // location.speed // 设备移动速度(单位米/秒) 100 // location.timestamp // 定位信息返回的时间 101 CLLocation *location = [locations lastObject]; 102 NSLog(@"纬度:%f, 经度:%f", location.coordinate.latitude, location.coordinate.longitude); 103 } 104 105 @end
实例二:定位信息计算
1 // ViewController.h文件 2 #import "ViewController.h" 3 #import <CoreLocation/CoreLocation.h> // 导入头文件 4 5 // 遵循定位协议<CLLocationManagerDelegate> 6 @interface ViewController ()<CLLocationManagerDelegate> 7 8 // CLLocationManager管理者对象 9 @property (nonatomic, strong) CLLocationManager *manager; 10 // 上一次的位置信息 11 @property (nonatomic, strong) CLLocation *lastLocation; 12 // 定位的总路程 13 @property (nonatomic, assign) CLLocationDistance totalDistance; 14 // 定位的总时间 15 @property (nonatomic, assign) NSTimeInterval totalTime; 16 17 @end 18 19 @implementation ViewController 20 21 #pragma mark - 懒加载 22 // 初始化创建CoreLocation管理者 23 - (CLLocationManager *)manager 24 { 25 if (_manager == nil) { 26 _manager = [[CLLocationManager alloc] init]; 27 } 28 return _manager; 29 } 30 31 - (void)viewDidLoad 32 { 33 [super viewDidLoad]; 34 35 // 设置代理 36 self.manager.delegate = self; 37 38 // 参数设置 39 // a.定位精准度(越精准越耗电) 40 self.manager.desiredAccuracy = kCLLocationAccuracyBest; 41 // b.每隔多少米定位一次(单位:米) 42 self.manager.distanceFilter = 5; 43 44 // iOS8以上:要求手动授权 45 if ([[UIDevice currentDevice] systemVersion].floatValue >= 8.0) { 46 // a.请求前台和后台的定位权限 47 [self.manager requestAlwaysAuthorization]; 48 // b.请求前台的定位权限 49 // [self.manager requestWhenInUseAuthorization]; 50 } else { 51 // 开始定位 52 [self.manager startUpdatingLocation]; 53 } 54 55 // iOS9:同一项目中允许多个定位对象并存,可随时代码控制某个定位对象的后台定位授权 56 if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) { 57 // 后台授权属性:allowsBackgroundLocationUpdates(YES:允许,NO:不允许) 58 self.manager.allowsBackgroundLocationUpdates = YES; 59 } 60 } 61 62 #pragma mark - 协议方法<CLLocationManagerDelegate> 63 // 1.用户授权状态一经改变就会调用 64 - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status 65 { 66 if (status == kCLAuthorizationStatusNotDetermined) { 67 NSLog(@"等待用户授权"); 68 }else if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) { 69 NSLog(@"授权成功"); 70 71 // 开始定位 72 [self.manager startUpdatingLocation]; 73 } else { 74 NSLog(@"授权失败"); 75 } 76 } 77 // 2.定位成功调用(调用频率非常高,所以要代码控制调用频率) 78 // 参数:locations 位置数组(上一位置、当前位置) 79 - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations 80 { 81 // location.coordinate // 坐标,包含经纬度 82 // location.altitude // 设置海拔高度(单位是米) 83 // location.course // 设置前进方向(0北/90东/180南/270西) 84 // location.horizontalAccuracy // 水平精准度 85 // location.verticalAccuracy // 垂直精准度 86 // location.speed // 设备移动速度(单位米/秒) 87 // location.timestamp // 定位信息返回的时间 88 89 90 // 现实开发中的问题 91 // 1.获取连续的两次定位一共走啦多远?(解决:当前位置 - 上一位置) 92 // 2.获取连续的两次定位走这段路花费多长时间?(解决:当前的时间戳 - 上一时间戳) 93 // 3.获取连续的两次定位走这段路程的平均速度?(解决:总路程 / 总时间) 94 // 4.累计走啦多远?(解决:每连续两次定位走的路程相加) 95 // 5.累计定位走啦多久?(解决:每连续两次定位走的时间相加) 96 // 6.累计的平均速度?(解决:总路程 / 总时间) 97 98 // 获取当前的位置信息 99 CLLocation *currentLocation = locations.lastObject; 100 // 判断上一次位置是否为空 101 if (self.lastLocation != nil) { 102 // 1.计算连续两次定位走的距离(米) 103 CLLocationDistance distance = [currentLocation distanceFromLocation:self.lastLocation]; 104 // 2.计算连续两次定位之间的时间(秒) 105 NSTimeInterval disTime = [currentLocation.timestamp timeIntervalSinceDate:self.lastLocation.timestamp]; 106 // 3.计算连续两次定位之间的平均速度(米/秒) 107 CGFloat speed = distance / disTime; 108 // 4.累加距离(米) 109 self.totalDistance += distance; 110 // 5.累加时间(秒) 111 self.totalTime += disTime; 112 // 6.计算整个的平均速度(米/秒) 113 CGFloat avgSpeed = self.totalDistance / self.totalTime; 114 115 NSLog(@"连续两次定位走的路程:%f, 连续两次定位走的时间:%f, 连续两次定位的平均速度:%f", distance, disTime, speed); 116 NSLog(@"总路程:%f, 总时间:%f, 平均速度:%f", self.totalDistance, self.totalTime, avgSpeed); 117 } 118 // 保存当前位置信息 119 self.lastLocation = currentLocation; 120 } 121 122 @end
实例三:获取用户地理方向
1 // ViewController.h文件 2 #import "ViewController.h" 3 #import <CoreLocation/CoreLocation.h> // 导入头文件 4 5 // 遵循定位协议<CLLocationManagerDelegate> 6 @interface ViewController ()<CLLocationManagerDelegate> 7 8 // CLLocationManager管理者对象 9 @property (nonatomic, strong) CLLocationManager *manager; 10 // 指南针图片 11 @property (nonatomic, strong) UIImageView *imageView; 12 @end 13 14 @implementation ViewController 15 16 #pragma mark - 懒加载 17 // 初始化创建CoreLocation管理者 18 - (CLLocationManager *)manager 19 { 20 if (_manager == nil) { 21 _manager = [[CLLocationManager alloc] init]; 22 } 23 return _manager; 24 } 25 26 - (void)viewDidLoad 27 { 28 [super viewDidLoad]; 29 30 // 1.添加指南针图片 31 _imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bg"]]; 32 _imageView.center = CGPointMake(self.view.center.x, self.view.center.y); 33 [self.view addSubview:_imageView]; 34 35 // 2.成为CoreLocation管理者的代理监听获取到的位置 36 self.manager.delegate = self; 37 38 // 3.开始获取用户位置 39 // 注意:获取用户的方向信息是不需要用户授权的 40 [self.manager startUpdatingHeading]; 41 } 42 #pragma mark - CLLocationManagerDelegate 43 // 当获取到用户方向时就会调用 44 - (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading 45 { 46 // 地理方向(CLHeading) 47 // newHeading.magneticHeading // 设备与磁北的相对角度(一般开发都是获取这个) 48 // newHeading.trueHeading // 设备与真北的相对角度(必须和定位一起使用) 49 50 // 1.将获取到的角度转为弧度 = (角度 * π) / 180; 51 CGFloat angle = newHeading.magneticHeading * M_PI / 180; 52 53 // 2.旋转图片 54 // transform 55 // 顺时针:正弧度 56 // 逆时针:负弧度 57 // self.compasspointer.transform = CGAffineTransformIdentity; // 清空旋转弧度 58 self.imageView.transform = CGAffineTransformMakeRotation(-angle); 59 } 60 61 @end
实例四:检测用户区域
1 // ViewController.h文件 2 #import "ViewController.h" 3 #import <CoreLocation/CoreLocation.h> // 导入头文件 4 5 // 遵循定位协议<CLLocationManagerDelegate> 6 @interface ViewController ()<CLLocationManagerDelegate> 7 8 // CLLocationManager管理者对象 9 @property (nonatomic, strong) CLLocationManager *manager; 10 11 @end 12 13 @implementation ViewController 14 15 #pragma mark - 懒加载 16 // 初始化创建CoreLocation管理者 17 - (CLLocationManager *)manager 18 { 19 if (_manager == nil) { 20 _manager = [[CLLocationManager alloc] init]; 21 } 22 return _manager; 23 } 24 25 - (void)viewDidLoad 26 { 27 [super viewDidLoad]; 28 29 // 设置代理 30 self.manager.delegate = self; 31 32 // 对于iOS8,请求用户主动授权 33 if ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0) { 34 [self.manager requestAlwaysAuthorization]; 35 } 36 // 对于iOS9,允许动态改变后台授权状态 37 if ([[UIDevice currentDevice].systemVersion doubleValue] >= 9.0) { 38 self.manager.allowsBackgroundLocationUpdates = YES; 39 } 40 41 // 创建区域对象 42 // CLRegion类有两个子类 43 // CLCircularRegion 地图上圆形区域 44 // CLBeaconRegion 蓝牙发射器信号区域 45 46 // 创建圆形区域 47 // 参数1:圆心(经纬度) 48 // 参数2:半径(米) 49 // 参数3:区域ID(类似于区域标识) 50 CLLocationCoordinate2D centerCoordinate2D = CLLocationCoordinate2DMake(40.058501, 116.304171); 51 CLCircularRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:centerCoordinate2D radius:200 identifier:@"circularRegionID"]; 52 53 // 开始检测用户所在的区域 54 [self.manager startMonitoringForRegion:circularRegion]; 55 } 56 57 #pragma mark - 协议方法<CLLocationManagerDelegate> 58 // 1.用户进入监测区域,就会调用 59 - (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region 60 { 61 NSLog(@"用户位于指定区域内"); 62 } 63 // 2.用户偏离监测区域,就会调用 64 - (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region 65 { 66 NSLog(@"用户已偏离指定区域"); 67 } 68 69 @end
5.CoreLocation的地理编码

浙公网安备 33010602011771号