概述
在移动互联网时代,很多社交类,团购类app都引入了地图,地图能解决用户的很多生活琐事,比如:
导航:去任意陌生的地方,汽车导航等
周边:找餐馆、找酒店、找银行、找电影院
总之,目前地图和定位功能已经大量引入到应用开发中。
在上述应用中,都用到了地图和定位功能,在iOS开发中,要想加入这2大功能,必须基于2个框架进行开发, Map Kit :用于地图展示 , Core Location :用于地理定位.
下面介绍地图经常使用的类和方法.
定位,地理编码(反编码)
- CLLocationManager
CLLocationManager的常用操作:
开始用户定位
- (void)startUpdatingLocation;
停止用户定位
- (void) stopUpdatingLocation;
当调用了startUpdatingLocation方法后,就开始不断地定位用户的位置,中途会频繁地调用代理的下面方法
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
locations参数里面装着CLLocation对象
- CLLocation
CLLocation用来表示某个位置的地理信息,比如经纬度、海拔等等
@property(readonly, nonatomic) CLLocationCoordinate2D coordinate; // 经纬度
@property(readonly, nonatomic) CLLocationDistance altitude; // 海拔
@property(readonly, nonatomic) CLLocationDirection course; // 路线,航向(取值范围是0.0° ~ 359.9°,0.0°代表真北方向)
@property(readonly, nonatomic) CLLocationSpeed speed; // 行走速度(单位是m/s)
@property(assign, nonatomic) CLLocationDistance distanceFilter; // 每隔多少米定位一次
@property(assign, nonatomic) CLLocationAccuracy desiredAccuracy; // 定位精确度(越精确就越耗电)
用- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location方法可以计算2个位置之间的距离
//第一个坐标
CLLocation *current=[[CLLocation alloc] initWithLatitude:32.178722 longitude:119.508619];
//第二个坐标
CLLocation *before=[[CLLocation alloc] initWithLatitude:32.206340 longitude:119.425600];
// 计算距离
CLLocationDistance meters=[current distanceFromLocation:before];
- 用户隐私
从iOS 8开始,用户定位分两种情况:
总是使用用户位置:NSLocationAlwaysUsageDescription
使用应用时定位:NSLocationWhenInUseDescription
当想访问用户的隐私信息时,系统会自动弹出一个对话框让用户授权,需要在info.plist中设置
为了严谨起见,最好在使用定位功能之前判断当前应用的定位功能是否可用
CLLocationManager有个类方法可以判断当前应用的定位功能是否可用
+ (BOOL)locationServicesEnabled;
iOS8需要先请求用户定位方式
第一种方式:
if ([self.mgr respondsToSelector:@selector(requestAlwaysAuthorization)]) {
// 获取授权
[self.mgr requestAlwaysAuthorization];
}
第二种方式:
if ([CLLocationManager locationServicesEnabled]){
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
// 获取授权
[self.locationManager requestAlwaysAuthorization];
}
}
- CLLocationCoordinate2D
CLLocationCoordinate2D是一个用来表示经纬度的结构体,定义如下
typedef struct {
CLLocationDegrees latitude; // 纬度
CLLocationDegrees longitude; // 经度
} CLLocationCoordinate2D;
一般用CLLocationCoordinate2DMake函数来创建CLLocationCoordinate2D
- CLGeocoder (地理编码,反地理编码)
使用CLGeocoder可以完成“地理编码”和“反地理编码”
地理编码:根据给定的地名,获得具体的位置信息(比如经纬度、地址的全称等)
反地理编码:根据给定的经纬度,获得具体的位置信息
地理编码方法:
- (void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;
反地理编码方法:
- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;
CLGeocodeCompletionHandler
当地理反地理编码完成时,就会调用CLGeocodeCompletionHandler
typedef void (^CLGeocodeCompletionHandler)(NSArray *placemarks, NSError *error);
这个block传递2个参数
error :当编码出错时(比如编码不出具体的信息)有值
placemarks :里面装着CLPlacemark对象
地理编码和反地理编码,在开发中是比较常用的,下面是一个简单的应用:
首先,使用storyBoard搭建界面,如下图:
代码实现:
/**
北京: 经度:116.28 纬度:39.54
重庆市: 北纬29.35 东经106.33
*/
#import "ViewController.h"
#import <MapKit/MapKit.h>
@interface ViewController ()
// 反地理编码
@property (weak, nonatomic) IBOutlet UITextField *longitudeField;
@property (weak, nonatomic) IBOutlet UITextField *latitudeField;
@property (weak, nonatomic) IBOutlet UILabel *reverseGeodeLable;
// 地理编码
@property (weak, nonatomic) IBOutlet UITextField *addressNameField;
@property (weak, nonatomic) IBOutlet UITextField *geocodeLongitudeField;
@property (weak, nonatomic) IBOutlet UITextField *geocodeLatitudeField;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
// 反地理编码 : 根据经纬度,获得具体位置信息
- (IBAction)reverGeocode:(UIButton *)sender {
// 取出经纬度
NSString *longitude = self.longitudeField.text;
NSString *latitude = self.latitudeField.text;
if (latitude.length == 0 || longitude.length == 0) return;
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
// 根据经纬度获取位置信息
CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude.floatValue longitude:longitude.floatValue];
// 反编码
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
if (!error) {
// 取得第一个地标,地标中存储了详细的地址信息,注意:一个地名可能搜索出多个地址
MKPlacemark *placemark = [placemarks firstObject];
// 位置
CLLocation *location = placemark.location;
// 区域
CLRegion *regin = placemark.region;
self.reverseGeodeLable.text = placemark.locality;
// 如果是取出城市的话,需要判断locality属性是否有值(直辖市时,该属性为空)
// self.reverseGeodeLable.text = placemark.locality ? placemark.locality : placemark.administrativeArea;
NSLog(@"%@ -------- %@",location,regin);
}
}];
}
// 地理编码 : 根据地名获取经纬度
- (IBAction)geocode:(UIButton *)sender {
// 地址
NSString