iOS8 - CoreLocation地图定位

CoreLocation

一、iOS 支持的定位方式

iOS 支持三种检测当前位置的方式:手机基站、Wi-Fi、和GPS,其中GPS是经度最高的,同时也是最耗费手机电量的。一般情况下在室内是无法通过GPS获 取位置信息的,通过Wi-Fi获取位置的原理是通过网络提供商的IP地址信息来获取位置,经度不是很高,最后是通过手机基站获取位置,手机开机后会连接附 近的基站塔获取信号,通过基站可以得到手机所在的位置信息,基站越密集,所获取的位置信息经度就越高。

二、iOS8 中定位的变化

在iOS8中,苹果已经强制开发者在请求定位服务时获得用户的授权,此外iOS状态栏中还有指示图标,提示用户当前应用是否正在使用定位服务。另外在iOS8中,苹果进一步改善了定位服务,让开发者请求定位服务时需要向用户提供更多的透明。此外,iOS8中还支持让应用开发者调用全新的“访问监控”功能,当用户允许后应用才能获得更多的定位数据。

三、iOS8 以前使用CoreLocation定位

1、首先定义一个全局的变量用来记录CLLocationManager对象,引入CoreLocation.framework

1
@property (nonatomic, strong) CLLocationManager *locationManager;

2、初始化CLLocationManager并开始定位

1
2
3
4
5
self.locationManager = [[CLLocationManager alloc]init];
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
_locationManager.distanceFilter = 10;
[_locationManager startUpdatingLocation];

3、实现CLLocationManagerDelegate的代理方法

(1)获取到位置数据,返回的是一个CLLocation的数组,一般使用其中的一个

  • (void)locationManager:(CLLocationManager )manager didUpdateLocations:(NSArray )locations {
    CLLocation *currLocation = [locations lastObject];
    NSLog(@”经度=%f 纬度=%f 高度=%f”, currLocation.coordinate.latitude, currLocation.coordinate.longitude, currLocation.altitude);

(2)获取经纬度失败的方法

1
2
3
4
5
6
7
8
9
10
11
12
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
if ([error code] == kCLErrorDenied) {
//访问被拒绝
} if ([error code] == kCLErrorLocationUnknown) {
//无法获取位置信息
}
}

4、在viewWillDisappear关闭定位

1
2
3
4
5
6
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[_locationManager stopUpdatingLocation];
}

四、iOS8 中使用CoreLocation定位

1、在使用CoreLocation前需要调用如下函数【iOS8专用】:

iOS8对定位进行了一些修改,其中包括定位授权的方法,CLLocationManager增加了下面的两个方法:

(1)始终允许访问位置信息

  • (void)requestAlwaysAuthorization;

(2)使用应用程序期间允许访问位置数据

  • (void)requestWhenInUseAuthorization;
1
2
3
4
5
6
self.locationManager = [[CLLocationManager alloc]init];
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
_locationManager.distanceFilter = 10;
[_locationManager requestAlwaysAuthorization];//添加这句
[_locationManager startUpdatingLocation];

2、在Info.plist文件中添加如下配置:

(1)NSLocationAlwaysUsageDescription

(2)NSLocationWhenInUseUsageDescription

CoreLocation

五、部分代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#import "LocationViewController.h"
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
@interface LocationViewController () <CLLocationManagerDelegate>
// CLLocationManager(位置管理器)
@property(nonatomic, strong) CLLocationManager *locationManager;
@end
@implementation LocationViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
// delegate:响应CLLocationManagerdelegate的对象
self.locationManager.delegate = self;
/*
desiredAccuracy:位置的精度属性:
kCLLocationAccuracyBest; 精确度最佳
kCLLocationAccuracyNearestTenMeters; 精确度10m以内
kCLLocationAccuracyHundredMeters; 精确度100m以内
kCLLocationAccuracyKilometer; 精确度1000m以内
kCLLocationAccuracyThreeKilometers; 精确度3000m以内
*/
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
// distanceFilter:横向移动多少距离后更新位置信息 位置发生100米偏移时 重新定位
self.locationManager.distanceFilter = 100;
if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
[self.locationManager requestAlwaysAuthorization];
// 需要在plist文件中添加默认缺省的字段“NSLocationAlwaysUsageDescription”,这个提示是:“允许应用程序在您并未使用该应用程序时访问您的位置吗?”NSLocationAlwaysUsageDescription对应的值是告诉用户使用定位的目的或者是标记。
// 需要在plist文件中添加默认缺省的字段“NSLocationWhenInUseDescription”,这个时候的提示是:“允许应用程序在您使用该应用程序时访问您的位置吗?”
[self.locationManager requestWhenInUseAuthorization];
}
// 开始定位
[self.locationManager startUpdatingLocation];
}
//#pragma mark -
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status) {
case kCLAuthorizationStatusNotDetermined:
if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
break;
default:
break;
}
}
#pragma mark - iOS8 之前获取经纬度的方法
//- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
//
// NSLog(@"经度 = %f 纬度 = %f", newLocation.coordinate.latitude, newLocation.coordinate.longitude);
// self.LatitudeLabel.text = [NSString stringWithFormat:@"%f", newLocation.coordinate.latitude];
// self.LongitudeLabel.text = [NSString stringWithFormat:@"%f", newLocation.coordinate.longitude];
//
//}
#pragma mark - CLLocationManagerDelegate
#pragma mark - 获取经纬度 并且根据经纬度进行反向编码
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *currLocation = [locations lastObject];
NSLog(@"经度=%f 纬度=%f", currLocation.coordinate.latitude, currLocation.coordinate.longitude);
// 关闭定位
[self.locationManager stopUpdatingLocation];
// 根据经纬度 反向编码 获取详细地址
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:currLocation
completionHandler:^(NSArray *placemarks, NSError *error){
for (CLPlacemark *place in placemarks) {
NSLog(@"thoroughfare,%@",place.thoroughfare); // 街道
NSLog(@"subThoroughfare,%@",place.subThoroughfare); // 子街道
NSLog(@"locality,%@",place.locality); // 市
NSLog(@"subLocality,%@",place.subLocality); // 区
NSLog(@"country,%@",place.country); // 国家
}
}];
}
@end