Core Location初心者

2015-08-07

最近项目中遇到需要通过 MKMapView 和 CLLocation 进行定位和商铺显示的需求,这几天把这些零散的知识点总结了一下,方便日后回顾。这篇博文主要先回顾 Core Location 相关内容。

先双手奉上demo代码

演示效果

Core Location 是 iOS 2.0 及之后用来定位的框架,在 iOS 3.0 后加入了定位手机方向的 API 。Core Location 能够定位到用户的位置靠的是 Wifi 定位蜂窝基站定位 GPS 定位。具体的定位方式不需要开发者考虑,iPhone 会根据不同场景选择不同定位方式。

那下面我们就来用示例程序看一下在项目中 Core Location 应该怎么结合进去。

CLLocationManager

首先,我们需要创建一个 CLLocation 服务的管理者 CLLocationManager ,设置代理。(当然,在这之前需要导入头文件 CoreLocation/CoreLocation.h)

1
2
self.locMgr = [[CLLocationManager alloc] init];
self.locMgr.delegate = self;

我们可以使用 startUpdatingLocationstopUpdatingLocation 来开始和结束定位.

1
2
[self.locMgr startUpdatingLocation];
[self.locMgr stopUpdatingLocation];

当成功获取到用户位置时,会通过回调函数通知控制器(调用频率非常频繁,在适当的时候应调用 stopUpdatingLocation 方法停止更新用户位置或者设置 CLLocationManager 的 distanceFilter 属性来对距离的改变进行筛选,即筛选设定距离以内的变化不会产生回调)

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

我们还可以通过设置 desiredAccuracy 属性来设置定位精度,我们可以将精度设为以下常量:

1
2
3
4
5
6
extern const CLLocationAccuracy kCLLocationAccuracyBestForNavigation;
extern const CLLocationAccuracy kCLLocationAccuracyBest;
extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;
extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;
extern const CLLocationAccuracy kCLLocationAccuracyKilometer;
extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;

大概第一步完成是这样子的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@interface ViewController () <CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locMgr;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.locMgr = [[CLLocationManager alloc] init];
self.locMgr.delegate = self;
self.locMgr.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.locMgr.distanceFilter = 50;
[self.locMgr startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
NSLog(@"%@", locations);
}
@end

运行程序,却出现了一个问题,在 iOS 7 上会弹出询问用户是否允许导航的提示,但是在 iOS 8 中却不会出现。

提示

iOS 8 对安全的要求更严格了(是因为 iCloud 泄密出去艳照的原因?),需要开发者通过代码手动去请求定位许可( WhenInUseAuthorizationAlwaysAuthorization ):

1
2
3
4
5
6
7
8
9
if ([self.locMgr respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[self.locMgr requestWhenInUseAuthorization];
// [self.locMgr requestAlwaysAuthorization];
}
// 也可以判断当前系统版本是否大于8.0,大于8.0时进行请求
// if ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0) {
// [self.locMgr requestWhenInUseAuthorization];
// }

光这样设置了还不够,运行程序依然没办法获得提示,我们需要到 Info.plist 里面配置一下(添加一项 NSLocationWhenInUseUsageDescription 或 NSLocationAlwaysUsageDescription ,根据不同项目需要选择)

info.plist

配置完成后就能够在 iOS 8 下看到提示了。

定位授权判断

在使用时我们需要判断程序定位功能是否被开启要怎么做呢?我们使用系统提供的 [CLLocationManager locationServicesEnabled] 这个方法。。。当然是不行的!!!这个方法仅仅判断了系统的定位服务是否开启,不能判断应用,所以我用了下面的方法进行判断:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 判断定位授权
*/
- (void)locationAuthorizationJudge {
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusNotDetermined) {
// 如果授权状态还没有被决定就弹出提示框
} else if (status == kCLAuthorizationStatusDenied) {
// 如果授权状态是拒绝就给用户提示
} else if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways) {
// 如果授权状态可以使用就开始获取用户位置
}
}

地理编码与反地理编码

地理编码主要用于把用户输入的内容转换成详细坐标的方法,而反地理编码则是通过输入经纬度来获取相对应的位置信息。两者的实现都需要地理编码器 CLGeocoder

在介绍地理编码与反地理编码之前先说下 CLPlacemark 这个类。从名称就可以看出,CLPlacemark是用来表示地标的类,包含的参数有:cllocationname(地标名),addressDictionary( A dictionary containing the Address Book keys and values for the placemark ),countrylocality 等等。

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

地理编码调用方法,返回一个 placemarks 的数组和一个 NSError 的对象。数组中存放的是 CLPlacemark 的对象。为什么会返回一个数组?因为同名的地方可能会有多个,例如“帝都”:

帝都

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

至于反地理编码,可以调用这个方法,将具体的经纬度坐标整合成 CLLocation 对象,和地理编码一样,完成后也会返回一个 placemarks 的数组和一个 NSError 的对象。具体效果看前面的演示吧。

模拟器定位

关于模拟器定位我这边的做法是给一个默认的位置,这个可以按照下图进行设置,我选的模拟位置是香港。

Edit Scheme

Location Simulation

部分需要配合真机测试的一些功能在这里就不展开了,感兴趣的童鞋可以研究下。