首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS-世界那么大,CoreLocation带你去看看

iOS-世界那么大,CoreLocation带你去看看

作者头像
xx_Cc
发布2018-05-10 11:35:45
1.3K0
发布2018-05-10 11:35:45
举报

一. 简介

在我们日常生活中时常用到地图和定位功能,来导航去你想去的地方或者寻找周边的景点,餐厅,电影院等等,在iOS开发中,要想加入这两大功能,必须基于两个框架进行开发,有了这两个框架,想去哪就去哪。 CoreLocation :用于地理定位,地理编码,区域监听等(着重功能实现) MapKit :用于地图展示,例如大头针,路线、覆盖层展示等(着重界面展示)

二. CoreLocation框架的基本使用

1. CoreLocation使用步骤
  1. 导入CoreLocation框架。
  2. 创建CLLocationManager管理者对象。
  3. 遵循代理,并实现代理方法。
  4. 设置获取用户前后台定位授权
  5. 开始定位。

三. CLLocationManager的使用

学习CLLocationManager可以分为三个部分。1.定位 2.手机朝向 3.区域监听

1. CLLocationManager -- 定位
先通过一个简单例子看一下
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
@interface ViewController ()<CLLocationManagerDelegate>
@property(nonatomic,strong)CLLocationManager *locationM;

@end

@implementation ViewController
-(CLLocationManager *)locationM
{
    if (_locationM == nil) {
        _locationM = [[CLLocationManager alloc]init];
        _locationM.delegate = self;
        // 只在前台开始定位  修改plist文件 提醒用户
        [_locationM requestWhenInUseAuthorization];
        // 前后台都可以定位  修改plist文件 提醒用户
        // [_locationM requestAlwaysAuthorization]; 
    }
    return _locationM;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    // 开始标准定位服务
    [self.locationM startUpdatingLocation];
    // 开启显著位置变化定位服务
    // [self.locationM startMonitoringSignificantLocationChanges];
}
#pragma mark CLLocationManagerDelegate代理方法
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    // manager 位置管理者       locations 位置数组
    // 在这里拿到位置信息做一些处理,这个方法会被持续调
    NSLog(@"--开始定位--");
}

注意: 1. 获取前台定位授权[_locationM requestWhenInUseAuthorization];需要在plist文件中加入NSLocationWhenInUseUsageDescription 获取前后台定位授权[_locationM requestAlwaysAuthorization]; 需要在plist文件中加入NSLocationAlwaysUsageDescription plist中加入的信息表示获取定位授权时显示的信息。

plist文件修改

运行程序请求用户授权时会弹出

请求用户授权

2. 开启标准定位服务使用的是GPS/WIFI定位,精确度较高,关闭应用程序就无法获取位置,而开启显著位置变化定位服务使用基站定位(必须有电话模块),当应用程序被关闭时,也可以接受到位置通知,并让app进入后台处理,但是定位精确度没有标准定位服务高,耗电少,定位更新频率依照基站密度而定,只要在基站范围内就显示基站位置,当进入另一个基站范围后更新。 如果要求定位及时,精确度高,并且运行时间短,可以使用标准定位服务。 如果长时间监控用户位置,用户移动速度较快,可使用显著位置变化定位服务 3. 代理方法didUpdateLocations会被持续调用,参数manager位置管理者 locations表示位置数组,里面按照时间先后顺序存储CLLocation对象,获取最后一个位置信息[locations lastObject]即可

CLLocationManager -- 关于定位属性和方法
// 判断定位功能是否可用
+ (BOOL)locationServicesEnabled
// 设置过滤单位(米)即每隔多少米定位一次
@property(assign, nonatomic) CLLocationDistance distanceFilter;  
// 设置定位精确度
@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;
CLLocationAccuracy kCLLocationAccuracyBestForNavigation  // 最适合导航的精确度
CLLocationAccuracy kCLLocationAccuracyBest; // 最好的
CLLocationAccuracy kCLLocationAccuracyNearestTenMeters; // 附近10米范围内
CLLocationAccuracy kCLLocationAccuracyHundredMeters; // 附近100米范围内
CLLocationAccuracy kCLLocationAccuracyKilometer; // 附近1000米范围内
CLLocationAccuracy kCLLocationAccuracyThreeKilometers; // 附近1000米范围内
// 开启定位
- (void)startUpdatingLocation
// 结束定位
- (void)stopUpdatingLocation;
CLLocationManagerDelegate -- 定位常用代理方法
// 定位成功 持续调用
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    // manager : 位置管理者       
    // locations : 位置数组
    // 在这里拿到位置信息做一些处理,这个方法会被持续调
}
// 定位失败时调用
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    // manager : 位置管理者       
    // error : 错误信息
}
// 当用户定位授权状态发生变化时调用
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    // manager : 管理者
    // status :状态
    /*
    kCLAuthorizationStatusNotDetermined = 0 // 用户未决定时
    kCLAuthorizationStatusRestricted // 受限制保留字段
    kCLAuthorizationStatusDenied // 被拒绝 1.被拒绝 2.未开启定位服务
    kCLAuthorizationStatusAuthorizedAlways // 前后台都可以定位授权
    kCLAuthorizationStatusAuthorizedWhenInUse // 前台定位授权
    */
}
CLLocation对象 -- 定位基本属性
// 根据经度和维度创建一个CLLocation对象
- (instancetype)initWithLatitude:(CLLocationDegrees)latitude
    longitude:(CLLocationDegrees)longitude;
// 经纬度,latitude经度 longitude维度
@property(readonly, nonatomic) CLLocationCoordinate2D coordinate;
// 高度位置 可以正面(海拔)或负面(低于海平面)。
@property(readonly, nonatomic) CLLocationDistance altitude;
// 水平精确度,如果是负值表示不可用
@property(readonly, nonatomic) CLLocationAccuracy horizontalAccuracy;
// 垂直精确度,如果是负值表示海拔不可用
@property(readonly, nonatomic) CLLocationAccuracy verticalAccuracy;
// 真北的位置度 取值 0.0 - 359.9 度  0 表示真北 
@property(readonly, nonatomic) CLLocationDirection course 
// 速度 m/s 负值表示速度无效
@property(readonly, nonatomic) CLLocationSpeed speed 
// 定位时间
@property(readonly, nonatomic, copy) NSDate *timestamp;
// 楼层,如果建筑物注册,可以获取楼层
@property(readonly, nonatomic, copy, nullable) CLFloor *floor 
// 返回位置
@property (nonatomic, readonly, copy) NSString *description;
// 计算两个坐标的物理直线距离
- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location 
2. CLLocationManager -- 设备方向
手机通过磁力计来判断设备方向,先看一个简单指南针的例子
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
@interface ViewController ()<CLLocationManagerDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property(nonatomic,strong)CLLocationManager *locationM;

@end

@implementation ViewController
-(CLLocationManager *)locationM
{
    if (_locationM == nil) {
        _locationM = [[CLLocationManager alloc]init];
        _locationM.delegate = self;
    }
    return _locationM;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    [self.locationM startUpdatingHeading];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
    /**
     *  CLHeading
     *  magneticHeading : 距离磁北方向的角度
     *  trueHeading : 距离真北方向的角度
     * headingAccuracy : 如果这个值是负数, 那么代表角度不可用
     */
    if (newHeading.headingAccuracy < 0) {
        return;
    }
    CGFloat angle = newHeading.magneticHeading;
    CGFloat r = angle * M_PI / 180;
    [UIView animateWithDuration:0.5 animations:^{
        self.imageView.transform = CGAffineTransformMakeRotation(-r);
    }];
}
CLLocationManager -- 关于手机朝向属性和方法
// 判断是否支持磁力计定位手机朝向
+ (BOOL)headingAvailable
// 开启手机朝向定位
- (void)startUpdatingHeading 
// 关闭手机朝向定位
- (void)stopUpdatingHeading
CLLocationManagerDelegaer -- 关于手机朝向的代理方法
// 当获取一个新朝向的时候调用,持续调用
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
    // manager : 管理者
    // newHeading : 朝向
}
CLHeading对象基本属性
// 与磁北方向的角度  范围 0.0 - 359.9 度, 0 度表示磁北方向
@property(readonly, nonatomic) CLLocationDirection magneticHeading;
// 与真北方向的角度  范围 0.0 - 359.9 度, 0 度表示真北方向
@property(readonly, nonatomic) CLLocationDirection trueHeading;
// 返回方向值的错误范围,负值表示无效的朝向
@property(readonly, nonatomic) CLLocationDirection headingAccuracy;
// 返回方向的时间
@property(readonly, nonatomic, copy) NSDate *timestamp;

注意:当获取朝向的时候不需要向用户请求授权,因为设备方向不涉及到用户隐私

3. CLLocationManager -- 区域监听

区域监听实例

#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
@interface ViewController ()<CLLocationManagerDelegate>
@property(nonatomic,strong)CLLocationManager *locationM;

@end

@implementation ViewController
-(CLLocationManager *)locationM
{
    if (_locationM == nil) {
        _locationM = [[CLLocationManager alloc]init];
        _locationM.delegate = self;
        [_locationM requestAlwaysAuthorization];
    }
    return _locationM;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    // 中心
    CLLocationCoordinate2D center = CLLocationCoordinate2DMake(67.666, 80.888);
    // 区域半径
    CLLocationDistance distance = 1000.0;
    CLCircularRegion *range = [[CLCircularRegion alloc]initWithCenter:center radius:distance identifier:@"ding"];
    // 用这个方法需要有位置的变化才行,从外部进来 或者出去才会有响应
    // [self.locationM startMonitoringForRegion:range];
    // 用这个方法就会先获取一次,判断是否在区域中
    [self.locationM requestStateForRegion:range];
}

-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    NSLog(@"进入区域");
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
    NSLog(@"出去区域");
}
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
    NSLog(@"%@",region);
    // 获取请求指定区域状态时调用的方法
    /**
     CLRegionStateUnknown, // 不知道
     CLRegionStateInside, // 在区域内部
     CLRegionStateOutside // 在区域外部
     */
    if(state == CLRegionStateInside)
    {
        NSLog(@"在区域中");
    }else if (state == CLRegionStateOutside)
    {
        NSLog(@"在区域外面");
    }
}
@end

注意: [self.locationM startMonitoringForRegion:range];开启区域监听,需要有位置的变化才会调用代理方法,例如位置从区域外部进入区域内部。 [self.locationM requestStateForRegion:range];程序一运行就会先确定在不在区域中,当位置发生改变时也会判断在不在区域中,是进入区域还是离开区域

CLLocationManager -- 关于区域间厅属性和方法
// 判断当前设备是否支持区域监听(区域类型)
+ (BOOL)isMonitoringAvailableForClass:(Class)regionClass
// 最大的区域大小,超过这个最大值后无效
@property (readonly, nonatomic) CLLocationDistance maximumRegionMonitoringDistance
// 开启一个区域的监听
- (void)startMonitoringForRegion:(CLRegion *)region 
// 请求一个区域的监听
- (void)requestStateForRegion:(CLRegion *)region 
CLLocationManagerDelegaer -- 关于区域监听的代理方法
// 进入区域时调用 manager : 管理者 region:区域
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
}
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
       state : 状态
       CLRegionStateUnknown, // 不知道
       CLRegionStateInside, // 在区域内部
       CLRegionStateOutside // 在区域外部
}
CLCircularRegion对象基本属性

CLCircularRegion是CLRegion的子类

// 创建方法 cente : 中心位置 radius : 区域半径 identidier : 唯一标示 
- (instancetype)initWithCenter:(CLLocationCoordinate2D)center
                            radius:(CLLocationDistance)radius
                        identifier:(NSString *)identifier;
// 中心位置
@property (readonly, nonatomic) CLLocationCoordinate2D center;
// 半径
@property (readonly, nonatomic) CLLocationDistance radius;
4. 地理编码和反地理编码

地理编码指 地址转经纬度,反地理编码指 经纬度转地址。使用CLGeocoder来获取。

CLGeocoder 的使用
// 创建
CLGeocoder *geocoder = [[CLGeocoder alloc]init];
// 地理编码
[self.geocoder geocodeAddressString:地址 completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
     if (error == nil) {
     }
}];
// 反地理编码
[self.geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
    if (error == nil) {
    }       
}];

注意:方法中返回的是一个装着CLPlacemark对象的数组,是对输入地址名称或者经纬度进行检索的结果,因此返回多个结果供选择。error指错误信息,如果错误error有值

CLPlacemark基本属性
// 对应的位置对象 参考CLLocation基本属性
@property (nonatomic, readonly, copy, nullable) CLLocation *location;
@property (nonatomic, readonly, copy, nullable) CLRegion *region; // 范围
@property (nonatomic, readonly, copy, nullable) NSTimeZone *timeZone // 时区
@property (nonatomic, readonly, copy, nullable) NSString *name; // 地址名称
@property (nonatomic, readonly, copy, nullable) NSString *thoroughfare; // 街道
@property (nonatomic, readonly, copy, nullable) NSString *subThoroughfare; // 街道相关信息,例如门牌
@property (nonatomic, readonly, copy, nullable) NSString *locality; // 城市
@property (nonatomic, readonly, copy, nullable) NSString *subLocality; // 城市内分区
@property (nonatomic, readonly, copy, nullable) NSString *administrativeArea; // 直辖市
@property (nonatomic, readonly, copy, nullable) NSString *subAdministrativeArea; // 其他行政区域信息
@property (nonatomic, readonly, copy, nullable) NSString *postalCode; // 邮编
@property (nonatomic, readonly, copy, nullable) NSString *ISOcountryCode; // 国家编码
@property (nonatomic, readonly, copy, nullable) NSString *country; // 国家
@property (nonatomic, readonly, copy, nullable) NSString *inlandWater; // 水源湖泊
@property (nonatomic, readonly, copy, nullable) NSString *ocean; // 海洋
@property (nonatomic, readonly, copy, nullable) NSArray<NSString *> *areasOfInterest; // 关联的或利益相关的地标

四. iOS9/iOS8/iOS8之前的定位适配

1. iOS8.0之前是默认请求授权,需要在plist文件中加入

iOS 8.0之前

设置后台执行

设置后台执行

2. iOS 8.0

使用[_locationM requestWhenInUseAuthorization]; 请求获取前台定位, [_locationM requestAlwaysAuthorization];请求获取前后台定位,并修改plist文件。

iOS8.0+请求授权

iOS8.0以上也可以在Background Modes中设置后台定位,但是当后台定位的时候,会出现一个蓝条提醒用户正在后台定位

后台定位提醒

3. iOS 9.0

iOS 9.0 与iOS8.0一样,唯一的区别在于,当在Background Modes中设置后台定位时,需要_locationM.allowsBackgroundLocationUpdates = YES;设置允许。 并且iOS 9.0中新添加了单次定位的方法[self.locationM requestLocation];只获取一次位置信息。 实现逻辑: (1) 按照定位精确度从低到高进行排序,逐个进行定位.如果在有效时间内, 定位到了精确度最好的位置, 那么就把对应的位置通过代理告知外界. (2) 如果获取到的位置不是精确度最高的那个,也会在定位超时后,通过代理告诉外界. 注意事项: (1) 必须实现代理的-locationManager:didFailWithError:方法 (2) 不能与startUpdatingLocation方法同时使用

五. 第三方框架LocationManager

第三方框架的使用非常简单,GitHub上已经讲解的很清晰。LocationManager是将CLLocationManager由代理向block的封装转换。CoreCLLocation使用代理,代码比较分散,第三方框架使用block来接收用户信息,并且额外增加了设置超时时间等功能,使用更简单方便易读。


文中如果有不对的地方欢迎指出。我是xx_cc,一只长大很久但还没有二够的家伙。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016.09.12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一. 简介
  • 二. CoreLocation框架的基本使用
    • 1. CoreLocation使用步骤
    • 三. CLLocationManager的使用
      • 1. CLLocationManager -- 定位
        • 2. CLLocationManager -- 设备方向
          • 3. CLLocationManager -- 区域监听
            • 4. 地理编码和反地理编码
            • 四. iOS9/iOS8/iOS8之前的定位适配
              • 1. iOS8.0之前是默认请求授权,需要在plist文件中加入
                • 2. iOS 8.0
                  • 3. iOS 9.0
                  • 五. 第三方框架LocationManager
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档