CoreLocation

CoreLocation

用于地理定位,地理编码,区域监听等(着重功能实现)

1、导入主头文件 #import <CoreLocation/CoreLocation.h>
2、使用CLLocationManager对象来做用户定位

iOS 8.0 以前

1.创建位置管理者

#pragma mark - lazy
- (CLLocationManager *)manager
{
    if (_manager == nil) {
        //1.创建位置管理者
        _manager = [[CLLocationManager alloc] init];
        //2.告诉外界位置 (代理、block)
        _manager.delegate = self;
        
        //设置每隔多远定位一次
        // 设置每隔多远定位一次(1次  111km/100m)
        // 最新的位置距离上一次位置之间的距离大于100m, 才会通过代理告诉外界
        //_locationM.distanceFilter = 100;
        
        //定位精确度
        _manager.desiredAccuracy = kCLLocationAccuracyBest;
    }
    return _manager  ;
}

定位精度

        //定位精度越高越耗电,定位时间越长
        // kCLLocationAccuracyBestForNavigation // 最适合导航
        // kCLLocationAccuracyBest; // 最好的
        // kCLLocationAccuracyNearestTenMeters; // 附近10米
        // kCLLocationAccuracyHundredMeters; // 100米
        // kCLLocationAccuracyKilometer; // 1000米
        // kCLLocationAccuracyThreeKilometers; // 3000米

使用位置管理者, 开始获取用户位置

    
   // 一旦调用了这个方法, 那么就会不断的获取用户位置信息, 然后告诉外界
    // 默认情况,只能在前台获取用户位置信息, 如果我们想要在后台获取位置, 必须勾选后台模式 location updates
    // 标准定位服务(基于gps/wifi/基站)
    [self.manager startUpdatingLocation]; //不停监听

代理CLLocationManagerDelegate

#pragma mark - CLLocationManagerDelegate
/**
 *  当获取到用户位置信息时调用
 *  @param manager   位置管理者
 *  @param locations 位置数组 
 */
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    NSLog(@"定位到了用户的信息");
    // 一般我们开发中, 获取到用户位置信息之后, 做一些业务逻辑操作
    // 针对于定位一次的情况, 可以在定位到之后 停止获取用户位置
//        [manager stopUpdatingLocation];
}
iOS8.0- 定位描述.png
后台模式.png
模拟器模拟位置变化.png
iOS 8.0 以后
8.0的API,主动请求用户授权

// 请求前台定位授权
- (void)requestAlwaysAuthorization  //请求允许在前后台都能获取用户位置的授权
// 默认情况下, 只能在前台获取用户位置
// 如果想要获取后台位置, 需要勾选后台模式 location updates , 但是会出现蓝条

// 请求前后台定位授权
- (void)requestWhenInUseAuthorization//请求允许在前台获取用户位置的授权
// 默认在前后台都可以获取用户位置信息, 无论是否勾选后台模式locaiton updates, 而且不会出现蓝条

iOS8.0后_前台授权说明.png
iOS8.0后_前后台授权说明.png
勾选后台模式.png
        //**-------ios8.0+定位适配---------- */
  1、if([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)
2、if([_locationM respondsToSelector:@selector(requestAlwaysAuthorization)])      {
    [_locationM requestAlwaysAuthorization];
 }

// 如果授权状态发生变化时,调用
// 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:UIApplicationOpenSettingsURLString];
                if([[UIApplication sharedApplication] canOpenURL:url])
                {
                    [[UIApplication sharedApplication] openURL:url];
                }
                
            }else
            {
                NSLog(@"定位服务关闭");
            }
            break;
        }
        case kCLAuthorizationStatusAuthorizedAlways:
        {
             NSLog(@"前后台定位授权");
            break;
        }
        case kCLAuthorizationStatusAuthorizedWhenInUse:
        {
            NSLog(@"前台定位授权");
            break;
        }
            
        default:
            break;
    }
    
}

iOS 9.0以后

 // 如果在iOS9.0+想要在前台授权模式下, 在后台获取用户位置, 我们需要额外的设置以下属性为YES
            if (isIOS(9.0)) {
                _locationM.allowsBackgroundLocationUpdates = YES;
            }

//前后台授权模式下,在后台定位还需要在plist文件里额外设置,如下图

iOS9.0后前后台授权模式额外设置.png

      // 请求一次位置信息
     // 注意 不能与startUpdatingLocation 一起使用
    if(isIOS(9.0))
    {

        [self.locationM requestLocation];
        /*
         按照定位精确度从低到高进行排序,逐个进行定位。如果获取到的位置不是精确度最高的那个,也会在定位超时后,通过代理告诉外界(必须实现代理的-locationManager:didFailWithError:方法, 不能与startUpdatingLocation方法同时使用)
         */
    }


// 当获取到用户位置信息时调用
// manager : 位置管理者
// locations: 位置数组 按时间进行排序, 如果想要拿到最新的位置, 直接拿最后一个
// id+泛型 is kind of
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)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];
    
}


区域监听


#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>

@interface ViewController ()<CLLocationManagerDelegate>

/** 位置管理者 */
@property (nonatomic, strong) CLLocationManager *locationM;

@property (weak, nonatomic) IBOutlet UILabel *noticeLabel;

@end

@implementation ViewController


#pragma mark -懒加载
-(CLLocationManager *)locationM
{
    if (!_locationM) {
        _locationM = [[CLLocationManager alloc] init];
        _locationM.delegate = self;
        
        // 主动请求定位授权
        if([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)
        [_locationM requestAlwaysAuthorization];
        
        
    }
    return _locationM;
}


- (void)viewDidLoad {
    
    /** 如果想要区域监听, 必须获取用户的定位授权 */

    // 监听的区域个数有限制
    
    // 判定某个区域对应的类, 能否被监听
    if([CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]])
    {
        // 0. 创建一个区域
        // 1.确定区域中心
        CLLocationCoordinate2D center = CLLocationCoordinate2DMake(21.123, 121.345);
        // 确定区域半径
        CLLocationDistance radius = 1000;
        
        // 使用前必须判定当前的监听区域半径是否大于最大可被监听的区域半径
        if(radius > self.locationM.maximumRegionMonitoringDistance)
        {
            radius = self.locationM.maximumRegionMonitoringDistance;
        }
        
        CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:radius identifier:@"小码哥"];
        // 区域监听
        //    [self.locationM startMonitoringForRegion:region];
        
        
        // 请求区域状态(如果发生了进入或者离开区域的动作也会调用对应的代理方法)  刚开始启动时候不知道是在进入还是离开
        [self.locationM requestStateForRegion:region];

    }
    
    
}



#pragma mark -CLLocationManagerDelegate
/**
 *  进入区域调用(是一个动作)
 *
 *  @param manager 位置管理者
 *  @param region  区域
 */
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    NSLog(@"进入区域");
    self.noticeLabel.text = @"小码哥欢迎你, 给你技术";
}

/**
 *  离开某个区域调用
 *
 *  @param manager 位置管理者
 *  @param region  区域
 */
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
    NSLog(@"离开区域");
      self.noticeLabel.text = @"祝大神三期找到30K";
}


/**
 *  请求某个区域的状态是调用
 *
 *  @param manager 位置管理者
 *  @param state   状态
 *  @param region  区域
 */
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
//    CLRegionStateUnknown,   未知状态
//    CLRegionStateInside, // 在区域内部
//    CLRegionStateOutside // 区域外面
    if(state == CLRegionStateInside)
    {
        self.noticeLabel.text = @"小码哥欢迎你, 给你技术";
    }else if (state == CLRegionStateOutside)
    {
         self.noticeLabel.text = @"祝大神三期找到30K";
    }
}

/**
 *  监听区域失败时调用
 *
 *  @param manager 位置管理者
 *  @param region  区域
 *  @param error   错误
 */
-(void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{
    // 经验: 一般在这里, 做移除最远的区域
    
//    [manager stopMonitoringForRegion:最远区域]
    
}


@end

地理编码和反地理编码

使用CLGeocoder可以完成“地理编码”和“反地理编码”

地理编码:根据给定的地名,获得具体的位置信息(比如经纬度、地址的全称等)

反地理编码:根据给定的经纬度,获得具体的位置信息


#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>

@interface ViewController ()


/** 地理编码 */
@property (nonatomic, strong) CLGeocoder *geoC;
@property (weak, nonatomic) IBOutlet UITextView *addressTV;

@property (weak, nonatomic) IBOutlet UITextField *latitudeTF;

@property (weak, nonatomic) IBOutlet UITextField *longitudeTF;
@end

@implementation ViewController


#pragma mark -懒加载
-(CLGeocoder *)geoC
{
    if (!_geoC) {
        _geoC = [[CLGeocoder alloc] init];
    }
    return _geoC;
}


-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //
    [self.view endEditing:YES];
}

/**
 *  地理编码(地址转经纬度)
 */
- (IBAction)geoCoder {
    
    NSString *address = self.addressTV.text;
    
    // 容错
    if([address length] == 0)
        return;
    
    [self.geoC geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        
        // CLPlacemark : 地标
        // location : 位置对象
        // addressDictionary : 地址字典
        // name : 地址详情
        // locality : 城市
        
        if(error == nil)
        {
            CLPlacemark *pl = [placemarks firstObject];
            self.addressTV.text = pl.name;
            self.latitudeTF.text = @(pl.location.coordinate.latitude).stringValue;
            self.longitudeTF.text = @(pl.location.coordinate.longitude).stringValue;
        }else
        {
            NSLog(@"错误");
        }

        
    }];
    
    
}
- (IBAction)reverseGeoCoder {
    
    // 获取用户输入的经纬度
    double latitude = [self.latitudeTF.text doubleValue];
    double longitude = [self.longitudeTF.text doubleValue];
    
    CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
    
    // 反地理编码(经纬度---地址)
    [self.geoC reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        if(error == nil)
        {
            CLPlacemark *pl = [placemarks firstObject];
            self.addressTV.text = pl.name;
            self.latitudeTF.text = @(pl.location.coordinate.latitude).stringValue;
            self.longitudeTF.text = @(pl.location.coordinate.longitude).stringValue;
        }else
        {
            NSLog(@"错误");
        }

    }];
    
    
}


@end


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

推荐阅读更多精彩内容