01-iOSCoreLocation框架的基本使用——定位
基本大纲
01-CoreLocation框架的基本使用—定位(iOS8.0-)
》iOS8.0- 的定位实现
》设置授权说明(段子写得好,用户授权的概率大)
》设置位置更新的距离过滤(防止过于频繁的调用代理方法)
》设置定位精度(精度越高,耗电越快。所以要根据需求选择合适的定位精度)
》后台定位(勾选后台模式:location update)
02-CoreLocation框架的基本使用—定位(iOS8.0+适配)
》iOS8.0+授权适配(两种适配方案:通过系统版本号,通过对象是否响应方法)(配置info.list文件中对应的键值)
》requestWhenInUseAuthorization 和 requestAlwaysAuthorization 区别(前者只有在APP前台时可以定位,后者可以在前后台进行定位)
》勾选后台运行模式location后的变化(在9.0之前,前者后台依然可以定位,但会出现蓝条;后者不会出现蓝条;)
》授权状态的变更,调用对应的代理方法(说明不同状态代表的含义,给予用户对应的提示)
》演示前后台授权和前台授权同时请求时会发生什么情况,并解释原因。
03-CoreLocation框架的基本使用—定位(iOS9.0补充)
》requestWhenInUseAuthorization 和 requestAlwaysAuthorization 区别(前者只有在APP前台时可以定位,后者可以在前后台进行定位)
》勾选后台运行模式location后的变化(效果同上,在while using the app 授权模式下,要想再次使用后台定位,必须使用allowsBackgroundLocationUpdates方法进行设置,但同样还是会出现蓝条)
》requestLocation 作用:按照定位精确度从低到高进行排序,逐个进行定位。如果获取到的位置不是精确度最高的那个,也会在定位超时后,通过代理告诉外界(必须实现代理的-locationManager:didFailWithError:方法, 不能与startUpdatingLocation方法同时使用)
好了,现在开始上代码
首先,引入框架、头文件
#import <CoreLocation/CoreLocation.h>
然后,使用CLLocationManager对象来做用户定位,那在使用之前,要创建对象,就简单给个需求,点击屏幕做用户定位
//遵循协议<CLLocationManagerDelegate>
@interface ViewController ()<CLLocationManagerDelegate>
//声明位置管理者属性
@property(nonatomic,strong)CLLocationManager * lm;
@end
#pragma mark - 懒加载
//既然只需要初始化以及,就用懒加载实现
-(CLLocationManager *)lm
{
if (!_lm) {
//1.创建位置管理者
_lm = [[CLLocationManager alloc] init];
//1.1 代理,通知,block(block优势,把代码集中到一起)
self.lm.delegate = self;
//每隔多远定位一次(位置过滤)
// _lm.distanceFilter = 100;
//定位的精确度
/*
kCLLocationAccuracyBestForNavigation 最适合导航
kCLLocationAccuracyBest; 最好的
kCLLocationAccuracyNearestTenMeters; 附近10米
kCLLocationAccuracyHundredMeters; 100m
kCLLocationAccuracyKilometer; 1000m
kCLLocationAccuracyThreeKilometers; 3000m
*/
//精确度越高,越耗电,定位时间长
_lm.desiredAccuracy = kCLLocationAccuracyBest;
/*-------iOS8.0+定位适配------*/
//方式1
if([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)
{
//前后台定位授权(请求永久授权)
//+authorizationStatus != kCLAuthorizationStatusNotDetermined(未授权状态)
//这个方法不会有效
[_lm requestAlwaysAuthorization];
//前台定位授权
// [_lm requestWhenInUseAuthorization];
}
if([[UIDevice currentDevice].systemVersion floatValue] >= 9.0)
{
/*--------iOS9.0之后需要添加的方法-------------*/
//允许后台运行,获取用户位置
//使用注意:一定要勾选后台模式 location updates
_lm.allowsBackgroundLocationUpdates = YES;
}
//方式2
// if ([_lm respondsToSelector:@selector(requestAlwaysAuthorization)]) {
// [_lm requestAlwaysAuthorization];
//
// }
return _lm;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//2.使用位置管理者,开始更新用户位置
//以后用这个类,做功能基本以start开头
[self.lm startUpdatingLocation];//不断更新用户信息
}
好了,运行程序。发现点击根本没反应,怎么办呢?那就点入授权方法的头文件看一看
什么意思呢?
在Info.plist文件中,没有NSLocationWhenInUseUsageDescription的key,那么这个方法就不会做任何事情。那简单了,在Info.plist文件中加入这个key就可以了。
点击屏幕,有提示框弹出
实现一些代理方法
更新到位置信息之后调用
/**
* 跟新到位置之后调用
*
* @param manager 位置管理者
* @param locations 位置数组
*/
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
NSLog(@"定位到了");
//拿到位置,做一些业务逻辑操作
//停止更新
// [manager stopUpdatingLocation];
}
授权状态发生改变时调用
/**
* 授权状态发生改变时调用
*
* @param manager 位置管理者
* @param status 状态
*/
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
}
iOS9.0之后又添加的方法,就写在touchesBegan里了
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//2.使用位置管理者,开始更新用户位置
//以后用这个类,做功能基本以start开头
// [self.lm startUpdatingLocation];//不断更新用户信息
//9.0之后多出的方法
/*
kCLLocationAccuracyBestForNavigation 最适合导航
kCLLocationAccuracyBest; 最好的
kCLLocationAccuracyNearestTenMeters; 附近10米
kCLLocationAccuracyHundredMeters; 100m
kCLLocationAccuracyKilometer; 1000m
kCLLocationAccuracyThreeKilometers; 3000m
*/
/**
* 注意,该方法必须响应locationManager:didFailWithError:(定位失败)方法
*
* 不能与startUpdatingLocation和allowDeferredLocationUpdates方法同时使用
* 进头文件里多看看
*/
[self.lm requestLocation];
}
//定位失败
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"定位失败");
}
04-CoreLocation框架的基本使用—CLLocation对象详解
》coordinate (当前位置所在的经纬度)
》altitude (海拔)
》speed (当前速度)
》-distanceFromLocation (获取两个位置之间的直线物理距离)
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// [self.lm startUpdatingLocation];
CLLocation * l1 = [[CLLocation alloc] initWithLatitude:45 longitude:289];
CLLocation * l2 = [[CLLocation alloc] initWithLatitude:43 longitude:289];
NSLog(@"%f",[l1 distanceFromLocation:l2]);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
NSLog(@"定位到了");
/**
* CLLocation 详解
* coordinate:经纬度
* altitude:海拔
* course:航向
* speed:速度
*/
CLLocation * location = [locations lastObject];
NSLog(@"%@",location);
}
场景演示:打印当前用户的行走方向,偏离角度以及对应的行走距离,
例如:”北偏东30度方向,移动了8米”
实现步骤:
1> 获取对应的方向偏向(例如”正东””东偏南”)
2> 获取对应的偏离角度(并判断是否是正方向)
3> 计算行走距离
4> 打印信息
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
CLLocation * location = [locations lastObject];
// NSLog(@"%@",location);
//方向
NSString * courseStr = nil;
switch ((int)location.course/90) {
case 0:
courseStr = @"北偏东";
break;
case 1:
courseStr = @"东偏南";
break;
case 2:
courseStr = @"南偏西";
break;
case 3:
courseStr = @"西偏北";
break;
default:
courseStr = @"找不到方向";
break;
}
//角度
NSInteger angle ;
angle = (int)location.course % 90;
//距离
//一开始起点位置为空,只有起点位置有值时才能去计算。之前设一个变量去记录
double distance = 0;
if (_oldLocation) {
distance = [location distanceFromLocation:_oldLocation];
}
_oldLocation = location;
//打印
NSString * noticeStr = [NSString stringWithFormat:@"%@%zd方向,移动了%fm",courseStr,angle,distance];
NSLog(@"%@",noticeStr);
}
05-CoreLocation框架的基本使用——指南针
》演示项目效果
实现思路:1.获取手机设备朝向(距离磁北方向的角度) 2. 让指南针图片反向旋转对应角度,这样就可以不断指向磁北
》获取手机朝向: [locationM startUpdatingHeading];
》magneticHeading(磁北方向和真北方向,取值范围:0-359.9;顺时针为正)
》注意:获取手机设备朝向不需要用户定位授权
//引入框架
#import <CoreLocation/CoreLocation.h>
//遵循协议
@interface ViewController ()<CLLocationManagerDelegate>
@property(nonatomic,strong)CLLocationManager * lm;//设置属性
@property (nonatomic,strong)UIImageView *compassView;
@end
//懒加载
-(CLLocationManager *)lm
{
if (!_lm) {
_lm = [[CLLocationManager alloc] init];
_lm.delegate = self;
// 每隔多少度更新一次
_lM.headingFilter = 2;
}
return _lm;
}
- (void)viewDidLoad {
[super viewDidLoad];
// 开始监听设备朝向
self.compassView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bg_compasspointer.png"]];
self.compassView.center = self.view.center;
[self.view addSubview:self.compassView];
}
#pragma mark - CLLocationManagerDelegate
/**
* 获取到手机朝向时调用
*
* @param manager 位置管理者
* @param newHeading 朝向对象
*/
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
/**
* CLHeading
* magneticHeading : 磁北角度
* trueHeading : 正北角度
*/
NSLog(@"%f", newHeading.magneticHeading);
CGFloat angle = newHeading.magneticHeading;
// 把角度转弧度
CGFloat angleR = angle / 180.0 * M_PI;
// 旋转图片
[UIView animateWithDuration:0.25 animations:^{
self.compassView.transform = CGAffineTransformMakeRotation(-angleR);
}];
}
06-CoreLocation框架的基本使用—区域监听
#import <CoreLocation/CoreLocation.h>
@interface ViewController ()<CLLocationManagerDelegate>
@property (nonatomic, strong) CLLocationManager *lm;
@end
-(CLLocationManager *)lm
{
if (!_lm) {
_lm = [[CLLocationManager alloc] init];
self.lm.delegate = self;
if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
[_lm requestAlwaysAuthorization];
//在Info.plist文件中,配置NSLocationAlwaysUsageDescription
}
}
return _lm;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//区域监听
CLLocationCoordinate2D center = {62.3,123.456};
CLCircularRegion * region = [[CLCircularRegion alloc] initWithCenter:center radius:200 identifier:@"FWL"];
// [self.lm startMonitoringForRegion:region];
//多区域监听
// CLLocationCoordinate2D center2 = {21.13, 123.456};
// CLCircularRegion *region2 = [[CLCircularRegion alloc] initWithCenter:center2 radius:1000 identifier:@"FWL2"];
// [self.lm startMonitoringForRegion:region2];
//请求区域状态
[self.lm requestStateForRegion:region];
}
#pragma mark - CLLocationManagerDelegate
//进入区域
-(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(@"%zd",state);
}
接下来就是重要的了,转到下一章。
呐,现在进入一个重要的知识点(我认为重要的)(反)地理编码
07-CoreLocation框架的基本使用—(反)地理编码
》CLGeocoder对象
》三种编码方案
》CLPlacemark讲解(locality:城市名称 thoroughfare:街道名称 name:全称 CLLocation *location)
》反地理编码
先用storyboard做一个界面
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextView *addressTV;
@property (weak, nonatomic) IBOutlet UITextField *laTF;
@property (weak, nonatomic) IBOutlet UITextField *longTF;
//地理编码
@property(nonatomic,strong)CLGeocoder * geocoder;
@end
@implementation ViewController
-(CLGeocoder *)geocoder
{
if (!_geocoder) {
_geocoder = [[CLGeocoder alloc] init];
}
return _geocoder;
}
//地理编码
- (IBAction)geoCoder {
NSString * addr = self.addressTV.text;
// 数据容错,一定要做
if ([addr length] == 0) {
return;
}
[self.geocoder geocodeAddressString:addr completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
if (error == nil) {
/**
* CLPlacemark
* location 位置对象
* addressDictionary 地址字典
*/
NSLog(@"%@",placemarks);
[placemarks enumerateObjectsUsingBlock:^(CLPlacemark * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"%@",obj.name);
self.addressTV.text = obj.name;
self.laTF.text = @(obj.location.coordinate.latitude).stringValue;
self.longTF.text = @(obj.location.coordinate.longitude).stringValue;
}];
}else{
NSLog(@"地理编码错误");
}
}];
}
//反地理编码
- (IBAction)reverseGeoCoder {
double lati = [self.laTF.text doubleValue];
double longti = [self.longTF.text doubleValue];
if (lati == 0.0|| longti == 0.0) {
return;
}
CLLocation * loc = [[CLLocation alloc] initWithLatitude:lati longitude:longti];
[self.geocoder reverseGeocodeLocation:loc completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
if (error == nil) {
[placemarks enumerateObjectsUsingBlock:^(CLPlacemark * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"%@",obj.name);
self.addressTV.text = obj.name;
self.laTF.text = @(obj.location.coordinate.latitude).stringValue;
self.longTF.text = @(obj.location.coordinate.longitude).stringValue;
}];
}else{
NSLog(@"反地理编码错误");
}
}];
}
数据容错,虽然简单,但是要做。
第三方框架的使用
08-CoreLocation框架的基本使用—定位的第三方框架
优点:可以使用block接收用户的位置,corelocation框架定位使用代理进行传值,代码比较分散
》下载框架(locationManager框架)
》使用block进行定位(带delayUntilAuthorized参数的定位:超时时间从什么时候开始计算)(依然要配置info.plist文件对应的键值对)
》通过定位请求ID分别取消定位(不会回调block)和强制完成定位(会回调block)
注意:此框架针对于iOS9.0 ,前台授权时,后台是无法获取用户位置
GitHub上搜索LocationManager,查看官方文档cao