一、简介
- 作用:用来表示某个位置的地理信息,比如经纬度、海拔等等
- 常用属性
// 经纬度
@property(readonly,nonatomic)CLLocationCoordinate2Dcoordinate;
// 海拔
@property(readonly,nonatomic)CLLocationDistance altitude;
// 路线,航向(取值范围是0.0°~359.9°,0.0°代表真北方向,是根据gps定位,获取的设备移动方向)
@property(readonly,nonatomic)CLLocationDirection course;
// 移动速度(单位是m/s),当前速度
@property(readonly,nonatomic)CLLocationSpeed speed;
```
- 方法:可以计算
2个位置之间的距离
-> 直线// 获取两个位置之间的直线物理距离 - (CLLocationDistance)distanceFromLocation:(constCLLocation*)location
二、基本使用
-
需求:打印当前用户的行走方向,偏离角度以及对应的行走距离,
- 例如:” 北偏东 30度 方向,移动了 8 米”
-
注意:
-
实现步骤:
- 1> 获取对应的方向偏向(例如”正东””东偏南”)
- 2> 获取对应的偏离角度(并判断是否是正方向)
- 3> 计算行走距离
- 4> 打印信息
-
思路分析:
-
1.确定确定航向
-
- 2.确定偏移角度
-
3.计算偏移距离
-
4.打印:
- 实现代码:
#import "ViewController.h"
#import
#define isIOS(version) ([[UIDevice currentDevice].systemVersion floatValue] >= version)
@interface ViewController ()
{
CLLocation *_lastLocation;
}
/** 位置管理者 */
@property (nonatomic, strong) CLLocationManager *locationM;
@end
@implementation ViewController
#pragma mark -懒加载
-(CLLocationManager *)locationM
{
if (!_locationM) {
//1 创建位置管理者
_locationM = [[CLLocationManager alloc] init];
// 1.1 告诉外界位置的方案: 代理, block 通知
_locationM.delegate = self;
// 设置每隔多远定位一次(1次 111km/100m)
// 最新的位置距离上一次位置之间的距离大于100m, 才会通过代理告诉外界
// _locationM.distanceFilter = 100;
// kCLLocationAccuracyBestForNavigation // 最适合导航
// kCLLocationAccuracyBest; // 最好的
// kCLLocationAccuracyNearestTenMeters; // 附近10米
// kCLLocationAccuracyHundredMeters; // 100米
// kCLLocationAccuracyKilometer; // 1000米
// kCLLocationAccuracyThreeKilometers; // 3000米
// 定位精确度
// 定位精确度越高, 越耗电, 而且, 定位时间越长
_locationM.desiredAccuracy = kCLLocationAccuracyBest;
//**-------ios8.0+定位适配---------- */
if(isIOS(8.0))
{
// 请求前台定位授权
// 默认情况下, 只能在前台获取用户位置
// 如果想要获取后台位置, 需要勾选后台模式 location updates , 但是会出现蓝条
[_locationM requestWhenInUseAuthorization];
// 如果在iOS9.0+想要在前台授权模式下, 在后台获取用户位置, 我们需要额外的设置以下属性为YES
if (isIOS(9.0)) {
_locationM.allowsBackgroundLocationUpdates = YES;
}
// 请求前后台定位授权
// 默认在前后台都可以获取用户位置信息, 无论是否勾选后台模式locaiton updates, 而且不会出现蓝条
// 如果当前的授权状态!=用户为选择状态, 那么这个方法不会有效
// [_locationM requestAlwaysAuthorization];
}
// 其它适配方案
// if([_locationM respondsToSelector:@selector(requestAlwaysAuthorization)])
// {
// [_locationM requestAlwaysAuthorization];
// }
}
return _locationM;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 2. 使用位置管理者, 开始获取用户位置
// 开发经验: start 开始某个服务 stop 停止某个服务
// 一旦调用了这个方法, 那么就会不断的获取用户位置信息, 然后告诉外界
// 默认情况,只能在前台获取用户位置信息, 如果我们想要在后台获取位置, 必须勾选后台模式 location updates
// 标准定位服务(基于gps/wifi/基站)
[self.locationM startUpdatingLocation];
// 监听重大位置的改变(基于基站进行定位 , 要求, 设备必须有电话模块)
// [self.locationM startMonitoringSignificantLocationChanges];
// kCLLocationAccuracyBestForNavigation // 最适合导航
// kCLLocationAccuracyBest; // 最好的
// kCLLocationAccuracyNearestTenMeters; // 附近10米
// kCLLocationAccuracyHundredMeters; // 100米
// kCLLocationAccuracyKilometer; // 1000米
// kCLLocationAccuracyThreeKilometers; // 3000米
// 请求一次位置信息
// 注意 不能与startUpdatingLocation 一起使用
if(isIOS(9.0))
{
// [self.locationM requestLocation];
}
}
#pragma mark -CLLocationManagerDelegate
// 当获取到用户位置信息时调用
// manager : 位置管理者
// locations: 位置数组 按时间进行排序, 如果想要拿到最新的位置, 直接拿最后一个
// id+泛型 is kind of
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
// coordinate : 经纬度坐标
// altitude : 海拔
// horizontalAccuracy :水平海拔 如果是负数, 代表当前位置不可用
// course : 航向(0---359.0)
// - distanceFromLocation : 方法来计算两个点之间的物理距离
// 判断当前位置是否可用
CLLocation *location = [locations lastObject];
if(location.horizontalAccuracy < 0)
return;
// 场景演示:打印当前用户的行走方向,偏离角度以及对应的行走距离,
// 例如:” 北偏东 30度 方向,移动了 8 米”
// 1. 确定航向
NSString *angleStr;
switch ((int)location.course / 90) {
case 0:
angleStr = @"北偏东";
break;
case 1:
angleStr = @"东偏南";
break;
case 2:
angleStr = @"南偏西";
break;
case 3:
angleStr = @"西偏北";
break;
default:
angleStr = @"掉沟里去了";
break;
}
// 2. 确定偏离角度
NSInteger angle = (int)location.course % 90;
if(angle == 0)
{
angleStr = [angleStr substringToIndex:1];
}
// 确定行走了多少米
double distance = 0;
if (_lastLocation) {
distance = [location distanceFromLocation:_lastLocation];
}
_lastLocation = location;
// 例如:” 北偏东 30度 方向,移动了 8 米”
NSString *noticeStr;
if (angle == 0) {
noticeStr = [NSString stringWithFormat:@"正%@方向, 移动了%f米", angleStr, distance];
}else
{
noticeStr = [NSString stringWithFormat:@"%@%zd方向, 移动了%f米", angleStr, angle, distance];
}
NSLog(@"%@", noticeStr);
// NSLog(@"定位到了--%@", location);
// 一般我们开发中, 获取到用户位置信息之后, 做一些业务逻辑操作
// 针对于定位一次的情况, 可以在定位到之后 停止获取用户位置
// [manager stopUpdatingLocation];
}
// 如果授权状态发生变化时,调用
// status : 当前的授权状态
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status) {
case kCLAuthorizationStatusNotDetermined:
{
NSLog(@"用户未决定");
break;
}
case kCLAuthorizationStatusRestricted:
{
NSLog(@"受限制");
break;
}
case kCLAuthorizationStatusDenied:
{
// 判断当前设备是否支持定位, 并且定位服务是否开启()
if([CLLocationManager locationServicesEnabled])
{
NSLog(@"定位开启,被拒绝");
// ios8,0- 需要截图提醒引导用户
// iOS8.0+
// NSURL *url = [NSURL URLWithString:]
// if([[UIApplication sharedApplication] openURL:<#(NSURL *)#>])
}else
{
NSLog(@"定位服务关闭");
}
break;
}
case kCLAuthorizationStatusAuthorizedAlways:
{
NSLog(@"前后台定位授权");
break;
}
case kCLAuthorizationStatusAuthorizedWhenInUse:
{
NSLog(@"前台定位授权");
break;
}
default:
break;
}
}
// 定位失败调用
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"定位失败");
}
@end
三、应用场景
-
- 导航
-
- 电商APP,获取用户所在城市
-
- 数据采集用户信息(例如,统计app使用分布)
-
- 查找周边(周边好友, 周边商家等等)
四、经验
- ** 为了给用户省电,你可以这样做 **
- 1)不需要获取用户位置时,一定要关闭定位服务:
- 2)如果能满足项目需求,尽可能的使用”监听显著位置变化”的定位服务(打车app)
- 3)如果可以,尽可能使用低精度的desiredAccuracy
- 4)如果是数据采集,(一般都是周期性的去轮询用户位置),在轮询期间一定要关闭定位