ios学习笔记之地图(上)

一 前言

ios8.0之后与ios8.0之前,对于CoreLocation的使用,还是有很大区别的。本文介绍下CLLocationManager类的基本使用、如何做简单的区域监听以及一个指南针小案例。

二 CLLocationManager类的基本使用及ios8.0与ios9.0的对比

首先要导入头文件
"#import <CoreLocation/CoreLocation.h>"

需要获取用户位置信息时,要创建CLLocationManager位置管理者对象。

创建一个位置管理者

@property (nonatomic, strong) CLLocationManager *lm;

现在先懒加载下lm对象

#pragma mark - 懒加载
- (CLLocationManager *)lm{
    if (!_lm) {
        _lm = [[CLLocationManager alloc] init];
        _lm.delegate = self; // 设置代理
//        每隔多少米定位一次,如果不设置该值就会频繁调用代理方法"didUpdateLocations"方法
        _lm.distanceFilter = 100;
        
// desiredAccuracy 属性的取值,查看头文件,搜索CLLocationAccuracy,可以找到如下内容
//  extern const CLLocationAccuracy kCLLocationAccuracyBestForNavigation // 最适合导航
//  extern const CLLocationAccuracy kCLLocationAccuracyBest; //最好的
//  extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;//10米
//  extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;//100米
//  extern const CLLocationAccuracy kCLLocationAccuracyKilometer;//1000米
//  extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;//300米
        
        
//        ios8.0之后的定位适配*********************************
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
            //        精确度越高,越耗电,定位时间越长
            _lm.desiredAccuracy = kCLLocationAccuracyBest;
            //        前台定位授权,默认情况下,不可以在后台获取位置,勾选后台模式location update
            [_lm requestWhenInUseAuthorization];
            //        前后台定位授权(请求永久授权,在Plist里添加key:NSLocationAlwaysUsageDescription)
//            [_lm requestAlwaysAuthorization];
        }

//        或者先判断_lm对象是否能够响应requestAlwaysAuthorization方法,能响应就执行,这样就不需要知道该方法是作用于8.0之后的
//        if ([_lm respondsToSelector:@selector(requestAlwaysAuthorization)]) {
//            [_lm requestAlwaysAuthorization];
//        }
        
    }
    return _lm;
}

在ios9.0后,又多了判断是否可以在后台更新位置allowsBackgroundLocationUpdates
那么我们的适配又要多一个判断

- (CLLocationManager *)lm{
    if (!_lm) {
        _lm = [[CLLocationManager alloc] init];
        _lm.delegate = self;
        _lm.distanceFilter = 100;
        
//        8.0定位适配*********************************
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
            _lm.desiredAccuracy = kCLLocationAccuracyBest;
            //        前台定位授权,默认情况下,不可以在后台获取位置,要勾选后台模式location update
           [_lm requestWhenInUseAuthorization];
            
        }

        //            ios9.0之后,期望进入后台也能定位,多了这个allowsBackgroundLocationUpdates属性需配置,进入后台运行时,顶部有蓝条,与8.0版本一样
//        所以遇到了版本是9.0的用户,又要适配下
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
//            command点击该属性进入文件查看,会发现警告你使用该属性时,一定要勾选后台模式location updates
            _lm.allowsBackgroundLocationUpdates = YES;
        }
    }
    return _lm;
}

当位置改变后,通过代理来告知我们。

// 点击屏幕,开始测试
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    [self.lm startUpdatingLocation];
    
//    [self.lm requestLocation];// 这个方法现在已经不常用了,了解即可,该方法头文件使用说明说,其不能与startUpdatingLocation or  allowDeferredLocationUpdates同时用
    
    
//    测试下distanceFromLocation方法,纬度上相差1度,地理上大概相差111km
//    CLLocation *lo1 = [[CLLocation alloc] initWithLatitude:21.77 longitude:22.99];
//    CLLocation *lo2 = [[CLLocation alloc] initWithLatitude:22.77 longitude:22.99];
//    CLLocationDistance distance = [lo1 distanceFromLocation:lo2];
//    NSLog(@"distance = %f",distance);
//    结果:2017-03-06 17:03:47.123 地图ios8.0+[90641:12476302] distance = 110733.934092   (大概是111km)
    
}

#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
    NSLog(@"定位到了");
    
//    拿到数组里最新的数据lastObject
    
    /**
     *  CLLocation详解
     *  coordinate :坐标,经纬度
     *  altitude:海拔
     *  course:航向
     *  speed:速度
     *  latitude:纬度
     *  longtitude:经度
     */
    CLLocation *location = [locations lastObject];
    
    /**
     * 场景演练:打印当前用户的行走方向,偏离角度以及对应的行走距离,
     * 例如:”北偏东30度方向,移动了8米”
     *
     */
    
//    1 获取方向偏向
    NSString *angleStr = nil;
    
    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 = 0;
    angle = (int)location.course % 90;
    
//    正方向
    if (angle == 0) {
        angleStr = [angleStr substringToIndex:1];
        
        angleStr = [NSString stringWithFormat:@"正%@",angleStr];
    }
    
    
//    3 移动多少米
    double distance = 0;
    if (_oldL) {
        distance = [location distanceFromLocation:_oldL];
    }
    
    _oldL = location;
//    4 拼串打印
    NSString *noticeStr = [NSString stringWithFormat:@"%@%zd度方向,移动了%f米",angleStr,angle,distance];
    NSLog(@"%@",noticeStr);
}


/**
 授权状态发生改变时调用

 @param manager 位置管理者
 @param status 状态
 */
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
//    CLAuthorizationStatus是枚举类型,我们可以依照源文件,来解析下当前的用户位置状态
    NSLog(@"status = %d",status);
    
    
}

/**
 定位失败(配合requestLocation方法)

 @param manager <#manager description#>
 @param error <#error description#>
 */
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
    
}

打开模拟器,选择你需要的模拟位置变化状态。

三 区域监听
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
@interface ViewController ()<CLLocationManagerDelegate>
@property (nonatomic, strong) CLLocationManager *lM;
@end

@implementation ViewController
// 懒加载
- (CLLocationManager *)lM{
    if (!_lM) {
        _lM = [[CLLocationManager alloc] init];
        _lM.delegate = self;
        
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
            [_lM requestAlwaysAuthorization];
        }
        
    }
    return _lM;
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
//    给定区域region,标识为@"qingyun"
    CLLocationCoordinate2D center = {21.33,123.99};
    CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:1000 identifier:@"qingyun"]; //identifier是用来标识具体是哪个区域的
//    开始监听区域region
    [self.lM startMonitoringForRegion:region];
    
    //    给定区域regin2,标识为@"qingyun2"
    CLLocationCoordinate2D center2 = {33.33,123.99};
    CLCircularRegion *regin2 = [[CLCircularRegion alloc] initWithCenter:center2 radius:1000 identifier:@"qingyun2"];
    //    开始监听区域region2
    [self.lM startMonitoringForRegion:regin2];
    
//    请求指定区域的状态(状态包括:1 无法监听到 2 在该区域内 3 在该区域外)
    [self.lM requestStateForRegion:region];
    
}

#pragma mark - CLLocationManagerDelegate
//进入区域,只有当你动态进入时,才会调用
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
    NSLog(@"进入区域,%@",region.identifier);
}

//离开区域,当你动态离开该区域时,才会调用
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region{
    NSLog(@"离开区域,%@",region.identifier);
}


// 获取某个指定区域的状态,是在该区域里面,还是在该区域外面,还是无法监听到
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{
    
    NSString *str = nil;
//    CLRegionStateUnknown,
//    CLRegionStateInside,
//    CLRegionStateOutside
    switch (state) {
        case CLRegionStateUnknown:
            str = @"CLRegionStateUnknown";
            break;
         case CLRegionStateInside:
            str = @"CLRegionStateInside";
            break;
        case CLRegionStateOutside:
            str = @"CLRegionStateOutside";
            break;
        default:
            str = @"我不知道";
            break;
    }
    
    NSLog(@"state = %@  region.identifier = %@",str,region.identifier);
    
}

//运行之后会打印:
//[94660:13100043] state = CLRegionStateInside  region.identifier = qingyun

//将模拟器经纬度从:{21.33,123.99}改成:{22.33,123.99}后会有如下打印:
//2017-03-10 11:13:48.246 CoreLocation-区域监听[94660:13100043] 离开区域,qingyun
//2017-03-10 11:13:48.247 CoreLocation-区域监听[94660:13100043] state = CLRegionStateOutside  region.identifier = qingyun



@end

模拟器Debug->Location->CustomLocation 可以修改下当前位置

四 指南针的基本实现

首先选择一个指南针图片到你的项目里

单纯的做指南针(指向的方向其实是磁极的南和北)是不需要授权的,因为获取用户方向不牵扯到用户隐私

#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
@interface ViewController ()<CLLocationManagerDelegate>
@property (nonatomic, strong) CLLocationManager *lm;
@property (weak, nonatomic) IBOutlet UIImageView *compass;

@end

@implementation ViewController
#pragma mark - 懒加载

- (CLLocationManager *)lm{
    if (!_lm) {
        _lm = [[CLLocationManager alloc] init];
        _lm.delegate = self;
//        每隔多少度更新一次
        _lm.headingFilter = 2;    
    }
    return _lm;
}

- (void)viewDidLoad {
    [super viewDidLoad];
//    开始更新设备朝向
    [self.lm startUpdatingHeading];
}


#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.compass.transform = CGAffineTransformMakeRotation(-angleR);
    }];

    
}


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

推荐阅读更多精彩内容

  • 简介 在移动互联网时代,移动app能解决用户的很多生活琐事,比如 周边:找餐馆、找KTV、找电影院等等 导航:根据...
    JonesCxy阅读 1,080评论 1 1
  • CoreLocation框架 一. iOS8.0之前的定位(✨✨✨✨✨) 前台定位导入CoreLocation框架...
    尼古拉斯赵四爷阅读 890评论 0 2
  • 地图(CoreLocation和MapKit) CoreLocation框架CoreLocationCLLocat...
    superWX阅读 11,049评论 11 51
  • 其一新剥的白花生子石炉是奶奶手砌请守护袋里的米我往溪边接水去 其二山的氧和泉的水一齐咕噜着锅盖干树枝的火苗儿听到也...
    杨树存阅读 490评论 1 1
  • 公子王孙鬼去怜, 从来冷眼不相关。 世间真意于何处? 唯有农人系语间。
    小启明星阅读 230评论 0 11