zoukankan      html  css  js  c++  java
  • iOS项目开发— CoreLocation的定位服务和地理编码与发编码实现

     

    一、CoreLocation简介

    1.在移动互联网时代,移动app能解决用户的很多生活琐事,比如

    (1)导航:去任意陌生的地方

    (2)周边:找餐馆、找酒店、找银行、找电影院

    2.在上述应用中,都用到了地图和定位功能,在iOS开发中,要想加入这2大功能,必须基于2个框架进行开发

    (1)Map Kit :用于地图展示

    (2)Core Location :用于地理定位

    3.两个热门专业术语

    (1)LBS :Location Based Service(基于定位的服务)

    (2)SoLoMo :Social Local Mobile(索罗门)

    二、CoreLocation框架的使用

    1.CoreLocation框架使用前提

    (1)导入框架

       

    说明:在Xcode5以后,不再需要我们手动导入

    (2)导入主头文件

      #import <CoreLocation/CoreLocation.h>

    2.CoreLocation框架使用须知

    CoreLocation框架中所有数据类型的前缀都是CL

    CoreLocation中使用CLLocationManager对象来做用户定位

    三、模拟位置

    说明:在对程序进行测试的时候,设置手机模拟器的模拟位置(经纬度)

        

    四、CoreLocation定位服务
         1.CLLocationManager

    CLLocationManager的常用操作和属性

    开始用户定位- (void)startUpdatingLocation;

    停止用户定位- (void) stopUpdatingLocation;

    说明:当调用了startUpdatingLocation方法后,就开始不断地定位用户的位置,中途会频繁地调用代理的下面方法

      - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;

    每隔多少米定位一次

      @property(assign, nonatomic) CLLocationDistance distanceFilter;

    定位精确度(越精确就越耗电)

      @property(assign, nonatomic) CLLocationAccuracy desiredAccuracy;

     2.CLLocation

    CLLocation用来表示某个位置的地理信息,比如经纬度、海拔等等

    (1)经纬度 

      @property(readonly, nonatomic) CLLocationCoordinate2D coordinate;

    (2)海拔 

      @property(readonly, nonatomic) CLLocationDistance altitude;

    (3)路线,航向(取值范围是0.0° ~ 359.9°,0.0°代表真北方向)

      @property(readonly, nonatomic) CLLocationDirection course;

    (4)行走速度(单位是m/s)

       @property(readonly, nonatomic) CLLocationSpeed speed;

    (5)计算2个位置之间的距离

      - (CLLocationDistance)distanceFromLocation:(const CLLocation *)location方法

    3.CLLocationCoordinate2D

    CLLocationCoordinate2D是一个用来表示经纬度的结构体,定义如下

    typedef struct {

            CLLocationDegrees latitude; // 纬度

            CLLocationDegrees longitude; // 经度

    } CLLocationCoordinate2D;

    一般用CLLocationCoordinate2DMake函数来创建CLLocationCoordinate2D

    五、代码示例

      1 //  Created by 鑫 on 14-10-22.
      2 //  Copyright (c) 2014年 梁镋鑫. All rights reserved.
      3 //
      4 
      5 #import "TXViewController.h"
      6 #import <CoreLocation/CoreLocation.h>
      7 @interface TXViewController ()<CLLocationManagerDelegate>
      8 /**
      9  *  地理编码
     10  */
     11 @property (nonatomic, strong) CLGeocoder *geocoder;
     12 /**
     13  *  定位管里
     14  */
     15 @property (nonatomic, strong) CLLocationManager *locMgr;
     16 @property(nonatomic ,strong)NSString *cityName;
     17 
     18 @end
     19 
     20 @implementation TXViewController
     21 - (CLGeocoder *)geocoder
     22 {
     23     if (!_geocoder) {
     24         self.geocoder = [[CLGeocoder alloc] init];
     25     }
     26     return _geocoder;
     27 }
     28  #pragma mark-懒加载
     29 - (CLLocationManager *)locMgr
     30 {
     31 #warning 定位服务不可用
     32     if(![CLLocationManager locationServicesEnabled]) return nil;
     33     
     34     if (!_locMgr) {
     35         // 创建定位管理者
     36         self.locMgr = [[CLLocationManager alloc] init];
     37         // 设置代理
     38         self.locMgr.delegate = self;
     39     }
     40     return _locMgr;
     41 }
     42 
     43 - (void)viewDidLoad
     44 {
     45     [super viewDidLoad];
     46 // 开始定位用户的位置
     47     [self.locMgr startUpdatingLocation];
     48     
     49     // 开始监控某个位置
     50     CLRegion *region = [[CLRegion alloc] init];
     51     /**
     52      ........
     53      */
     54     [self.locMgr startMonitoringForRegion:region];
     55     //定位的精确度
     56      self.locMgr.desiredAccuracy=kCLLocationAccuracyThreeKilometers;
     57     
     58 }
     59 
     60 //
     61 ///**
     62 // *  计算2个经纬度之间的直线距离
     63 // */
     64 //- (void)countLineDistance
     65 //{
     66 //    // 计算2个经纬度之间的直线距离
     67 //    CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:40 longitude:116];
     68 //    CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:41 longitude:116];
     69 //    CLLocationDistance distance = [loc1 distanceFromLocation:loc2];
     70 //    NSLog(@"%f", distance);
     71 //}
     72 
     73 #pragma mark - CLLocationManagerDelegate
     74 /**
     75  *  只要定位到用户的位置,就会调用(调用频率特别高)定位管理器 代理方法,定位完毕时侯调用
     76  *  @param locations : 装着CLLocation对象
     77  */
     78 - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
     79 {
     80     // 1.取出位置对象
     81     CLLocation *loc = [locations firstObject];
     82     
     83     
     84     // 2.取出经纬度
     85     CLLocationCoordinate2D coordinate = loc.coordinate;
     86     CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
     87     //反地理编码
     88     [self.geocoder reverseGeocodeLocation:loc1 completionHandler:^(NSArray *placemarks, NSError *error) {
     89          CLPlacemark *pm = [placemarks firstObject];
     90         // 从字典中取出 state---->某某市
     91          NSString *cityName = pm.addressDictionary[@"State"];
     92         self.cityName = cityName;
     93         NSLog(@"%@",self.cityName);
     94         NSLog(@"%@",loc1);
     95         NSLog(@"%@",pm.name);
     96     }];
     97     
     98     // 3.打印经纬度
     99     NSLog(@"didUpdateLocations------%f %f", coordinate.latitude, coordinate.longitude);
    100     
    101     // 停止定位(省电措施:只要不想用定位服务,就马上停止定位服务)
    102     [manager stopUpdatingLocation];
    103 }
    104 
    105 
    106 @end
    View Code

    打印查看:

      

    代码说明:

    1.关于代理方法

      需要设置代理,通过代理告诉用户当前的位置,有两个代理方法:

      locations参数里面装着CLLocation对象

    其中后者是一个过期的方法,在新的方法(第一个)中使用了一个数组来替代。
    说明:该方法在当定位到用户的位置时就会调用,调用比较频繁
    注意:不要使用局部变量(创建位置管理器),因为局部变量的方法结束它就被销毁了。建议使用一个全局的变量,且只创建一次就可以了(使用懒加载)。
     
    2.定位的精度
      
    3.如果发现自己的定位服务没有打开,那么应该提醒用户打开定位服务功能。
    4.定位服务是比较耗电的,如果是做定位服务(没必要实时更新的话),那么定位了用户位置后,应该停止更新位置。
     
    六、用户隐私的保护

    1.权限设置说明

    从iOS 6开始,苹果在保护用户隐私方面做了很大的加强,以下操作都必须经过用户批准授权

    (1)要想获得用户的位置

    (2)想访问用户的通讯录、日历、相机、相册等

    当想访问用户的隐私信息时,系统会自动弹出一个对话框让用户授权

    注意:一旦用户选择了“Don’t Allow”,意味着你的应用以后就无法使用定位功能,且当用户第一次选择了之后,以后就再也不会提醒进行设置。

    因此在程序中应该进行判断,如果发现自己的定位服务没有打开,那么应该提醒用户打开定位服务功能。

    CLLocationManager有个类方法可以判断当前应用的定位功能是否可用+ (BOOL)locationServicesEnabled;

      常用的方法:截图告诉用户,应该怎么打开授权
      

    2.开发者可以在Info.plist中设置NSLocationUsageDescription说明定位的目的(Privacy - Location Usage Description)

      

    说明:(1)以上iOS7可行,iOS8变了,配置变成如下

            (2)这里的定位服务是基于网络的。通常定位服务可以是基于GPS、基站或者是网络的。

    七、CoreLocation地理编码

    CLGeocoder:地理编码器,其中Geo是地理的英文单词Geography的简写。

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

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

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

    (1)地理编码方法

      - (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler; 

    (2)反地理编码方法

      - (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;

    2.CLGeocodeCompletionHandler

      当地理反地理编码完成时,就会调用CLGeocodeCompletionHandler

      

    这个block传递2个参数

    error :当编码出错时(比如编码不出具体的信息)有值

    placemarks :里面装着CLPlacemark对象

       3.CLPlacemark

    说明:CLPlacemark的字面意思是地标,封装详细的地址位置信息

    地理位置     @property (nonatomic, readonly) CLLocation *location;  

    区域       @property (nonatomic, readonly) CLRegion *region;

    详细的地址信息   @property (nonatomic, readonly) NSDictionary *addressDictionary;

    地址名称    @property (nonatomic, readonly) NSString *name;

    城市      @property (nonatomic, readonly) NSString *locality;

    二、代码示例:

    在storyboard中搭建界面如下:

      

    实现代码:

      1 //  Created by 鑫 on 14-10-22.
      2 //  Copyright (c) 2014年 梁镋鑫. All rights reserved.
      3 //
      4 
      5 #import "TXViewController.h"
      6 #import <CoreLocation/CoreLocation.h>
      7 @interface TXViewController ()
      8 
      9 @property (nonatomic, strong) CLGeocoder *geocoder;
     10 
     11 #pragma mark - 地理编码
     12 - (IBAction)geocode;
     13 @property (weak, nonatomic) IBOutlet UITextField *addressField;
     14 @property (weak, nonatomic) IBOutlet UILabel *longitudeLabel;
     15 @property (weak, nonatomic) IBOutlet UILabel *latitudeLabel;
     16 @property (weak, nonatomic) IBOutlet UILabel *detailAddressLabel;
     17 
     18 #pragma mark - 反地理编码
     19 - (IBAction)reverseGeocode;
     20 @property (weak, nonatomic) IBOutlet UITextField *longtitudeField;
     21 @property (weak, nonatomic) IBOutlet UITextField *latitudeField;
     22 @property (weak, nonatomic) IBOutlet UILabel *reverseDetailAddressLabel;
     23 
     24 @end
     25 
     26 @implementation TXViewController
     27 
     28 - (CLGeocoder *)geocoder
     29 {
     30     if (!_geocoder) {
     31         self.geocoder = [[CLGeocoder alloc] init];
     32     }
     33     return _geocoder;
     34 }
     35 
     36 - (void)viewDidLoad
     37 {
     38     [super viewDidLoad];
     39     
     40 }
     41 
     42 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
     43 {
     44     [self.view endEditing:YES];
     45 }
     46 
     47 /**
     48  *  地理编码
     49  */
     50 - (IBAction)geocode {
     51      //1.获得输入的地址
     52     NSString *address = self.addressField.text;
     53     if (address.length == 0) return;
     54     //2.开始地理编码
     55          //说明:调用下面的方法开始编码,不管编码是成功还是失败都会调用block中的方法
     56     [self.geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
     57         //如果有错误信息,或者是数组中获取的地名元素数量为0,那么说明没有找到
     58         if (error) { // 有错误(地址乱输入)
     59             self.detailAddressLabel.text = @"你找的地址可能只在外星球才能找到!!!";
     60         } else { // 编码成功 找到了具体的位置信息
     61             // 取出最前面的地址
     62             CLPlacemark *pm = [placemarks firstObject];
     63             
     64             // 设置经纬度
     65             self.latitudeLabel.text = [NSString stringWithFormat:@"%.1f", pm.location.coordinate.latitude];
     66             self.longitudeLabel.text = [NSString stringWithFormat:@"%.1f", pm.location.coordinate.longitude];
     67             
     68             // 设置具体地址
     69             self.detailAddressLabel.text = pm.name;
     70             
     71             //打印查看找到的所有的位置信息
     72             //            NSLog(@"总共找到%d个地址", placemarks.count);
     73             //
     74             //            for (CLPlacemark *pm in placemarks) {
     75             //                NSLog(@"-----地址开始----");
     76             //
     77             //                NSLog(@"%f %f %@", pm.location.coordinate.latitude, pm.location.coordinate.longitude, pm.name);
     78             //
     79             //                [pm.addressDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
     80             //                    NSLog(@"%@ %@", key, obj);
     81             //                }];
     82             //
     83             //                NSLog(@"-----地址结束----");
     84             //            }
     85         }
     86     }];
     87 }
     88 
     89 /**
     90  *  反地理编码
     91  */
     92 - (IBAction)reverseGeocode {
     93     // 1.包装位置
     94     CLLocationDegrees latitude = [self.latitudeField.text doubleValue];
     95     CLLocationDegrees longitude = [self.longtitudeField.text doubleValue];
     96     CLLocation *loc = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
     97     
     98     // 2.反地理编码
     99     [self.geocoder reverseGeocodeLocation:loc completionHandler:^(NSArray *placemarks, NSError *error) {
    100         if (error) { // 有错误(地址乱输入)
    101             self.reverseDetailAddressLabel.text = @"你找的地址可能来自星星的!!!";
    102         } else { // 编码成功
    103             // 取出最前面的地址
    104             CLPlacemark *pm = [placemarks firstObject];
    105             
    106             // 设置具体地址
    107             self.reverseDetailAddressLabel.text = pm.name;
    108             //            NSLog(@"总共找到%d个地址", placemarks.count);
    109             //
    110             //            for (CLPlacemark *pm in placemarks) {
    111             //                NSLog(@"-----地址开始----");
    112             //
    113             //                NSLog(@"%f %f %@", pm.location.coordinate.latitude, pm.location.coordinate.longitude, pm.name);
    114             //
    115             //                [pm.addressDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
    116             //                    NSLog(@"%@ %@", key, obj);
    117             //                }];
    118             //
    119             //                NSLog(@"-----地址结束----");
    120             //            }
    121         }
    122     }];
    123 }
    124 @end
    125  
    View Code

    实现效果:

    (1)地理编码:(地名->经纬度坐标)

      

    打印输出:

      

    (2)反地理编码:(经纬度—>地名)

       

    (3)注意:搜索的所有结果都是在中国境内的,因为苹果在中国的地图服务商是高德地图。

     
     
  • 相关阅读:
    Linux基础命令(二)
    Linux基础命令(一)
    安装Centos 7操作系统
    网络基础之网络协议
    操作系统简介
    计算机硬件知识
    VS快捷键
    VB.NET 编程元素支持更改总结
    VB.Net中确认退出对话框的实现
    VB定义变量
  • 原文地址:https://www.cnblogs.com/asd5551680/p/4182005.html
Copyright © 2011-2022 走看看