最近项目中遇到需要通过MKMapView和CLLocation进行定位和商铺显示的需求,这几天把这些零散的知识点总结了一下,方便日后回顾。这篇博文主要先回顾Core Location相关内容。
先双手奉上demo代码。
演示效果
Core Location是iOS2.0及之后用来定位的框架,在iOS3.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;
|
我们可以使用startUpdatingLocation和stopUpdatingLocation来开始和结束定位.
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
|
@interface ViewController ()
@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
|
运行程序,却出现了一个问题,在iOS7上会弹出询问用户是否允许导航的提示,但是在iOS8中却不会出现。
提示
或许是因为iOS8对安全的要求更严格了(是因为iCloud泄密出去艳照的原因?),需要开发者通过代码手动去请求定位许可(WhenInUseAuthorization或AlwaysAuthorization):
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,根据不同项目需要选择)
配置完成后就能够在iOS8下看到提示了。
定位授权判断
在使用时我们需要判断程序定位功能是否被开启要怎么做呢?我们使用系统提供的[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是用来表示地标的类,包含的参数有:cllocation,name(地标名),addressDictionary(A dictionary containing the Address Book keys and values for the placemark),country,locality等等。
1
|
- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
|
地理编码调用方法,返回一个placemarks的数组和一个NSError的对象。数组中存放的是CLPlacemark的对象。为什么会返回一个数组?因为同名的地方可能会有多个,例如“帝都”:
1
|
- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
|
至于反地理编码,可以调用这个方法,将具体的经纬度坐标整合成CLLocation对象,和地理编码一样,完成后也会返回一个placemarks的数组和一个NSError的对象。具体效果看前面的演示吧。
模拟器定位
关于模拟器定位我这边的做法是给一个默认的位置,这个可以按照下图进行设置,我选的模拟位置是香港。
部分需要配合真机测试的一些功能在这里就不展开了,感兴趣的童鞋可以研究下。