地图

1>地图

iOS开发中,想要加入地图和定位功能,必须基于两个框架进行开发

MapKit:用于地图展示

CoreLocation:用于地理定位

2>地图定位

CoreLocation框架的使用

导入框架:(iOS5之后不再需要

导入头文件:#import<CoreLocation/CoreLocation.h>

CoreLocation框架使用须知

  • CoreLocation框架中所有数据类型的前缀都是CL
  • CoreLocation中使用CLLocationManager对象来做用户定位

CLLocationManager定位管理器类的常用操作:

1、开启用户定位

 1 - (void)startUpdatingLocation; 

2、停止用户定位

 1 - (void) stopUpdatingLocation; 

3、当调用了startUpdatingLocation方法后,就开始不断地定位用户的位置,中途会频繁地调用下面的代理方法,参数locations中的元素对象是CLLocation对象

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

4、每隔多少米定位一次

 1 @property(assign, nonatomic) CLLocationDistance distanceFilter; 

5、定位精确度,越精确就越耗电

 1 @property(assign, nonatomic) CLLocationAccuracy desiredAccuracy; 

6、CLLocationAccuracy 是一个枚举值

最佳导航
  kCLLocationAccuracyBestForNavigation
最精准
     kCLLocationAccuracyBest;
10米
     kCLLocationAccuracyNearestTenMeters;
百米
   kCLLocationAccuracyHundredMeters;
千米
     kCLLocationAccuracyKilometer;
3千米
     kCLLocationAccuracyThreeKilometers;

实现定位只需要下面几步:

1.  创建管理者对象
  self.manager = [[CLLocationManager alloc] init];
2.  设置代理
  self.manager.delegate = self;
3.  开启定位
  [self.manager startUpdatingLocation];

注意:从iOS 7之后,苹果在保护用户隐私方面做了很大的加强,以下操作都必须经过用户批准授权:
①要想获得用户的位置和访问用户的通讯录、日历、相机、相册等等都需要用户来手动授权。
②当想访问用户的隐私信息时,系统会自动弹出一个对话框让用户授权 

4 、请求授权 (授权方式根据实际情况进行选择)
 [self.manager requestAlwaysAuthorization];  // 请求前台和后台定位
 [self.manager requestWhenInUseAuthorization];  // 试用期间定位

请求授权后开发者需要在info.plist中设置NSLocationWhenInUseUsageDescription说明定位的目的(Privacy - Location Usage Description)

请求了哪几种授权就要设置它们对应的NSLocationUsageDescription

requestAlwaysAuthorization 对应的NSLocationUsageDescription是NSLocationAlwaysUsageDescription

requestWhenInUseAuthorization 对应的NSLocationUsageDescription是NSLocationWhenInUseUsageDescription

注:NSLocationWhenInUseUsageDescription来告诉用户使用定位服务的目的,并且注意这个配置是必须的,如果不进行配置则默认情况下应用无法使用定位服务,打开应用不会给出打开定位服务的提示,除非安装后自己设置此应用的定位服务。由于本人机器已经更新到最新的iOS8.1下面的内容主要针对iOS8,使用iOS7的朋友需要稍作调整

运行程序时会询问是否允许使用定位功能

一旦用户选择了“Don‘t Allow”,意味着你的应用以后就无法使用定位功能,为了严谨起见,最好在使用定位功能之前进行判断当前的应用定位功能是否可用

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

开启定位服务,代码展示:

 1 #import "ViewController.h"
 2 // 第一步:引入头文件
 3 #import <CoreLocation/CoreLocation.h>
 4 
 5 @interface ViewController ()<CLLocationManagerDelegate>  // 遵循CLLocationManager代理
 6 // CoreLocation 框架中的 CLLocationManager 用于管理定位的管理器
 7 // 定位管理器
 8 @property (nonatomic,strong) CLLocationManager *manager;
 9 
10 @end
11 
12 @implementation ViewController
13 
14 - (void)viewDidLoad {
15     [super viewDidLoad];
16     // 定位的步骤
17     // 第一步:初始化定位管理器
18     self.manager = [[CLLocationManager alloc] init];
19 
20     // 第二步:进行隐私的判断并授权
21     if (![CLLocationManager locationServicesEnabled]) {
22         NSLog(@"是否前往隐私设置,允许定位");
23     }
24     // 根据状态进行授权
25     // 进行版本的判断
26     if ([[[UIDevice currentDevice] systemVersion] integerValue] >= 8.0) {
27         if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
28             // 在授权请求之前需要在inforPlist中设置允许定位的内容 (两种状态)
29             // NSLocationWhenInUseUsageDescription
30             // NSLocationAlwaysUsageDescription
31             // 请求授权
32             [self.manager requestWhenInUseAuthorization];
33         }
34     }
35     // 第三步:设置管理器的代理和相关属性
36     self.manager.delegate = self;
37     // 设置精度
38     self.manager.desiredAccuracy = 100;
39     // 设置最小更新距离
40     self.manager.distanceFilter = 100;
41     // 第四步:开启定位
42     [self.manager startUpdatingLocation];
43 }
44 
45 @end

定位服务授权状态,返回枚举类型:

  •     kCLAuthorizationStatusNotDetermined 用户尚未做出决定是否启用定位服务
  •     kCLAuthorizationStatusRestricted 没有获得用户授权使用定位服务,可能用户没有自己禁止访问授权
  •     kCLAuthorizationStatusDenied :用户已经明确禁止应用使用定位服务或者当前系统定位服务处于关闭状态
  •     kCLAuthorizationStatusAuthorizedAlways 应用获得授权可以一直使用定位服务,即使应用不在使用状态
  •     kCLAuthorizationStatusAuthorizedWhenInUse 使用此应用过程中允许访问定位服务

4>地理编码和地理反编码

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

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

声明属性

 1 // CLGeocoder 能进行地理位置的编码和反编码 2 // 编码和反编码的类 3 @property (nonatomic,strong) CLGeocoder *geocoder;  

为了方便代码管理,创建几个方法来实现地理编码和地理反编码

1 // 地理编码方法
2 - (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
3 
4 // 反地理编码方法
5 - (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;

CLLocationCoordinate2D

 CLLocationCoordinate2D是一个用来表示经纬度的结构体,定义如下
typedef struct {
    CLLocationDegrees latitude; // 纬度
    CLLocationDegrees longitude; // 经度
} CLLocationCoordinate2D;

一般用CLLocationCoordinate2DMake函数来创建CLLocationCoordinate2D

模拟位置

如果是模拟器,需要设置模拟位置(经纬度)
北京的经纬度是:北纬40°,东经116°
大连的经纬度是:北纬39°,东经121°
郑州的经纬度是:北纬34°,东经113°
上海的经纬度是:北纬31°,东经121°
广州的经纬度是:北纬23°,东经113°
西安的经纬度是:北纬34°,东经108°

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

CLGeocodeCompletionHandler

1 // 当地理编码/反地理编码完成时,就会调用CLGeocodeCompletionHandler
2 typedef void (^CLGeocodeCompletionHandler)(NSArray *placemarks, NSError *error);
3 
4 block包含2个参数
5 error:当编码出错时(比如编码不出具体的信息),2其错误信息会包含在error中
6 placemarks:里面装着CLPlacemark对象 

CLPlacemark 

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

 1 // 地理位置
 2 @property (nonatomic, readonly) CLLocation *location;
 3 
 4 // 区域
 5 @property (nonatomic, readonly) CLRegion *region;
 6 
 7 // 详细的地址信息
 8 @property (nonatomic, readonly) NSDictionary *addressDictionary;
 9 
10 // 地址名称
11 @property (nonatomic, readonly) NSString *name;
12 
13 // 地点名称 
14 @property (nonatomic, readonly) NSString *locality;

1、根据地名获取经纬度

 1 #pragma mark - 根据地名获取经纬度
 2 - (void)getCoordinateByAddress:(NSString *)address {
 3     // 编码方法
 4     [_geocoder geocodeAddressString:address completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
 5         // 根据返回的地标取出第一个位置(地标的位置很多)
 6         CLPlacemark *mark = placemarks.firstObject;
 7         // 根据地标获取location
 8         CLLocation *location = mark.location;
 9         CLLocationCoordinate2D const coordinate = location.coordinate;
10         // 根据location获取区域
11         CLRegion *region = mark.region;
12         // 获取字典信息
13         NSDictionary *dic = mark.addressDictionary;
14         NSLog(@"location:%f, %f,\n\n region:%@,\n\n dic:%@", coordinate.latitude, coordinate.longitude, region, dic);
15     }];
16 }

2、根据经纬度获取地名

 1 #pragma mark - 根据经纬度获取地名
 2 - (void)getAddressByLatitude:(CLLocationDegrees)latitude Longitude:(CLLocationDegrees)longitude {
 3     // 反编码
 4     // 创建CLLocation
 5     CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
 6     [_geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
 7         // addressDictionary 详细的地理信息
 8         NSDictionary *dic = placemarks.firstObject.addressDictionary;
 9         NSLog(@"反编码地理位置信息:%@", dic);
10 //        NSLog(@"error: %@", error);
11     }];
12 }

3、计算两点之间的距离

1 #pragma mark - 计算两点之间的距离
2 - (void)distance {
3     // 创建位置1
4     CLLocation *locationBJ = [[CLLocation alloc] initWithLatitude:40 longitude:116];
5     CLLocation *locationDL = [[CLLocation alloc] initWithLatitude:39 longitude:121];
6     // 两个地方的距离
7     CLLocationDistance distance = [locationBJ distanceFromLocation:locationDL];
8     NSLog(@"距离:%f", distance);
9 }

4、实现定位成功的代理方法

 1 #pragma mark - CLLocationManagerDelegate 方法
 2 // 这个代理方法是定位成功后开始更新位置信息,只要移动设置的最小距离之后就开始运行这个方法
 3 - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
 4     // 获取最后一次的地址
 5     CLLocation *location = locations.lastObject;
 6     CLLocationCoordinate2D const coordinate = location.coordinate;
 7     // longitude 经度 latitude 纬度
 8     NSLog(@"纬度:%f, 经度:%f, 海拔:%f, 航向:%f, 速度:%f", coordinate.latitude, coordinate.longitude, location.altitude, location.course, location.speed);
 9     // 为了节省电源,如果不使用定位,需要把定位关掉
10     [self.manager stopUpdatingLocation];
11 }

注意:

 1.定位频率和定位精度并不应当越精确越好,需要视实际情况而定,因为越精确越耗性能,也就越费电。

 2.定位成功后会根据设置情况频繁调用-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations方法,这个方法返回一组地理位置对象数组,每个元素一个CLLocation代表地理位置信息(包含经度、纬度、海报、行走速度等信息),之所以返回数组是因为有些时候一个位置点可能包含多个位置。

 3.使用完定位服务后如果不需要实时监控应该立即关闭定位服务以节省资源。

 4.除了提供定位功能,CLLocationManager还可以调用startMonitoringForRegion:方法对指定区域进行监控。

5、实现定位失败的代理方法

1 #pragma mark - 定位失败的方法
2 - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
3     NSLog(@"定位失败error:%@", error);
4 }

placemark的属性

 1 //        addressDictionary   详细的地理信息
 2 //        NSString *name=placemark.name;//地名
 3 //        NSString *thoroughfare=placemark.thoroughfare;//街道
 4 //        NSString *subThoroughfare=placemark.subThoroughfare; //街道相关信息,例如门牌等
 5 //        NSString *locality=placemark.locality; // 城市
 6 //        NSString *subLocality=placemark.subLocality; // 城市相关信息,例如标志性建筑
 7 //        NSString *administrativeArea=placemark.administrativeArea; // 8 //        NSString *subAdministrativeArea=placemark.subAdministrativeArea; //其他行政区域信息
 9 //        NSString *postalCode=placemark.postalCode; //邮编
10 //        NSString *ISOcountryCode=placemark.ISOcountryCode; //国家编码
11 //        NSString *country=placemark.country; //国家
12 //        NSString *inlandWater=placemark.inlandWater; //水源、湖泊
13 //        NSString *ocean=placemark.ocean; // 海洋
14 //        NSArray *areasOfInterest=placemark.areasOfInterest; //关联的或利益相关的地标

 

posted @ 2016-06-01 00:06  Leo-Wmw  阅读(247)  评论(0)    收藏  举报