定位功能

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];//不断更新用户信息    
}

好了,运行程序。发现点击根本没反应,怎么办呢?那就点入授权方法的头文件看一看

屏幕快照01.png

什么意思呢?
Info.plist文件中,没有NSLocationWhenInUseUsageDescription的key,那么这个方法就不会做任何事情。那简单了,在Info.plist文件中加入这个key就可以了。

屏幕快照02.png

点击屏幕,有提示框弹出


屏幕快照 03.png

实现一些代理方法
更新到位置信息之后调用

/**
 *  跟新到位置之后调用
 *
 *  @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做一个界面


屏幕快照04.png
#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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352

推荐阅读更多精彩内容