定位服务

前言:

现在很多社交、电商、团购应用都引入了地图和定位功能,似乎地图功能不再是地图应用和导航应用所特有的。的确,有了地图和定位功能确实让我们的生活更加丰富多彩,极大的改变了我们的生活方式。例如你到了一个陌生的地方想要查找附近的酒店、超市等就可以打开软件搜索周边;类似的,还有很多团购软件可以根据你所在的位置自动为你推荐某些商品。总之,目前地图和定位功能已经大量引入到应用开发中。在产品研发中有两个专业术语需要大家知道:一是LBS(Location Based Service)基于定位的服务,二是SoLoMo(Social Local Mobile )社交本地的移动应用,这都是需要我们提供地图和定位服务。

在后面的课程里就和大家一起看一下iOS如何进行地图和定位开发。iOS系统为了方便我们开发,提供了地图服务的框架。除此之外,实际的开发工作中,我们常常会使用一些第三发的SDK来实现地图服务,主要有高德地图和百度地图,这些我们后在后面的几节中讲到。

地图功能的实现离不开定位服务,下面我们还是先来看一下iOS系统的定位功能是如何实现的。


1. 定位服务

要实现地图、导航功能,往往需要先熟悉定位功能,iOS中的定位引擎是CoreLocation框架提供的,我们通过CoreLocation框架进行定位操作。CoreLocation自身可以单独使用,和地图开发框架MapKit完全是独立的,但是往往地图开发要配合定位框架使用。在Core Location中主要包含了定位、地理编码(包括反编码)功能。

我们先介绍一下iOS定位功能的实现。定位是一个很常用的功能,如一些地图软件打开之后如果用户允许软件定位的话,那么打开软件后就会自动锁定到当前位置,如果用户手机移动那么当前位置也会跟随着变化。要实现这个功能需要使用CoreLoaction中CLLocationManager类,首先看一下这个类的一些主要方法和属性:

类方法

说明

  • (BOOL)locationServicesEnabled;

是否启用定位服务,通常如果用户没有启用定位服务可以提示用户打开定位服务

  • (CLAuthorizationStatus)authorizationStatus;

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

kCLAuthorizationStatusNotDetermined: 用户尚未做出决定是否启用定位服务

kCLAuthorizationStatusRestricted: 没有获得用户授权使用定位服务,可能用户没有自己禁止访问授权

kCLAuthorizationStatusDenied :用户已经明确禁止应用使用定位服务或者当前系统定位服务处于关闭状态

kCLAuthorizationStatusAuthorizedAlways: 应用获得授权可以一直使用定位服务,即使应用不在使用状态

kCLAuthorizationStatusAuthorizedWhenInUse: 使用此应用过程中允许访问定位服务

属性 说明
desiredAccuracy 定位精度,枚举类型:kCLLocationAccuracyBest:最精确定位CLLocationAccuracy kCLLocationAccuracyNearestTenMeters:十米误差范围kCLLocationAccuracyHundredMeters:百米误差范围kCLLocationAccuracyKilometer:千米误差范围kCLLocationAccuracyThreeKilometers:三千米误差范围
distanceFilter 位置信息更新最小距离,只有移动大于这个距离才更新位置信息,默认为kCLDistanceFilterNone:不进行距离限制
对象方法 说明
startUpdatingLocation 开始定位追踪,开始定位后将按照用户设置的更新频率执行-(void)locationManager:(CLLocationManager*)manager didUpdateLocations:(NSArray *)locations;方法反馈定位信息
stopUpdatingLocation 停止定位追踪
startUpdatingHeading 开始导航方向追踪
stopUpdatingHeading 停止导航方向追踪
startMonitoringForRegion: 开始对某个区域进行定位追踪,开始对某个区域进行定位后。如果用户进入或者走出某个区域会调用- (void)locationManager:(CLLocationManager )manager didEnterRegion:(CLRegion )region和- (void)locationManager:(CLLocationManager )manager didExitRegion:(CLRegion )region代理方法反馈相关信息
stopMonitoringForRegion: 对某个区域进行定位追踪
requestWhenInUseAuthorization 请求获得应用使用时的定位服务授权,注意使用此方法前在要在info.plist中配置NSLocationWhenInUseUsageDescription
requestAlwaysAuthorization 请求获得应用一直使用定位服务授权,注意使用此方法前要在info.plist中配置NSLocationAlwaysUsageDescription
代理方法 说明
-(void)locationManager:(CLLocationManager )manager didUpdateLocations:(NSArray )locations; 位置发生改变后执行(第一次定位到某个位置之后也会执行)
-(void)locationManager:(CLLocationManager )manager didUpdateHeading:(CLHeading )newHeading; 导航方向发生变化后执行
-(void)locationManager:(CLLocationManager )manager didEnterRegion:(CLRegion )region 进入某个区域之后执行
-(void)locationManager:(CLLocationManager )manager didExitRegion:(CLRegion )region 走出某个区域之后执行

除了CLLocationManager之外,CLLocation类也是在我们做定位服务中经常看到的,CLLocation常用来表示某个位置的地理信息,比如经纬度、海拔高度等,当然他也给我们提供了计算两个地理位置之间间距的方法。下面我们看一下CLLocation的常用属性和方法:

方法 说明
-(instancetype)initWithLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude; 初始化CLLocation,传入经纬度
-(instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate altitude:(CLLocationDistance)altitude horizontalAccuracy:(CLLocationAccuracy)hAccuracy verticalAccuracy:(CLLocationAccuracy)vAccuracy timestamp:(NSDate *)timestamp 初始化CLLocation,传入经纬度、定位精度和定位时间
-(instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate altitude:(CLLocationDistance)altitude horizontalAccuracy:(CLLocationAccuracy)hAccuracy verticalAccuracy:(CLLocationAccuracy)vAccuracy course:(CLLocationDirection)course speed:(CLLocationSpeed)speed timestamp:(NSDate *)timestamp; 初始化CLLocation,传入经纬度、定位精度和定位时间、定位路线、当前速度
-(CLLocationDistance) getDistanceFrom:(const CLLocation *); 计算两个点之间的距离
-(CLLocationDistance) distanceFromLocation:(const CLLocation *) 计算两个点之间的距离
属性 说明
@property(readonly, nonatomic) CLLocationCoordinate2D coordinate; 经纬度,结构体,一般通过函数CLLocationCoordinate2DMake来创建
@property(readonly, nonatomic) CLLocationDistance altitude; 海拔
@property(readonly, nonatomic) CLLocationAccuracy horizontalAccuracy; 水平定位精度
@property(readonly, nonatomic) CLLocationAccuracy verticalAccuracy; 竖直定位精度
@property(readonly, nonatomic) CLLocationDirection course; 路线,航线(范围在0-359.9之间,0代表正北方向)
@property(readonly, nonatomic) CLLocationSpeed speed; 行走速度(m/s)
@property(readonly, nonatomic, copy) NSDate *timestamp; 时间标记

一般在开始定位之前,应用会向用户获取授权请求,在iOS7及以前的版本,如果在应用程序中使用定位服务只要在程序中调用startUpdatingLocation方法应用就会询问用户是否允许此应用是否允许使用定位服务,同时在提示过程中可以通过在info.plist中配置通过配置Privacy -Location Usage Description告诉用户使用的目的,当然这个配置是可选的。但是在iOS8中配置配置项发生了变化,我们可以通过配置NSLocationAlwaysUsageDescription或者 NSLocationWhenInUseUsageDescription来告诉用户使用定位服务的目的,并且注意这个配置是必须的,如果不进行配置则默认情况下应用无法使用定位服务,打开应用不会给出打开定位服务的提示,除非安装后自己设置此应用的定位服务。同时,在应用程序中需要根据配置对requestAlwaysAuthorization或locationServicesEnabled方法进行请求。

iOS8提供了更加人性化的定位服务选项。应用的定位服务不再仅仅是关闭或打开。现在,定位服务的启用提供了三个选项:永不、使用应用程序期间、和始终。同时,考虑到能耗问题,如果一款 App 要求始终能在后台开启定位服务,iOS 8 不仅会在首次打开 App 时主动向你询问,还会在日常使用中弹窗提醒你该 App 一直在后台使用定位服务,并询问你是否继续允许。

下面我们就来看一看iOS实现定位服务的具体步骤有哪些

  • 判断硬件是否开启了定位服务
  • 判断应用是否获取定位授权
  • 初始化定位管家的对象,注意需要设置为全局变量
  • 设置定位权限:iOS8的新特性,可以实现代理方法获取授权范围。注意需要修改plist文件NSLocationAlwaysUsageDescription/NSLocationWhenInUseUsageDescription。
  • 设置定位服务的属性。
  • 开启定位,实现代理方法,获取定位信息

示例代码

#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>

@interface ViewController ()<CLLocationManagerDelegate>

// 定位服务管家
@property (nonatomic, strong)CLLocationManager *locationManager;

@end

@implementation ViewController
/*定位的实现
 1.导入框架 CoreLocation.framework
 2.导入库文件 #import <CoreLocation/CoreLocation.h>
 3.需要将定位管家 CLLocationManager 设置为全区变量

 1.判断硬件是否开启了定位服务
 2.初始化定位管家的对象,注意需要设置为全局变量
 3.判断定位服务授权状态,设置定位权限:iOS8的新特性,可以实现代理方法获取授权范围。注意需要修改plist文件 NSLocationAlwaysUsageDescription/NSLocationWhenInUseUsageDescription。
 4.设置定位服务的属性。
 5.开启定位,实现代理方法,获取定位信息
 */

- (void)viewDidLoad {
    [super viewDidLoad];

    // 1.判断硬件是否开启了定位服务
    BOOL isOpen = [CLLocationManager locationServicesEnabled];

    if (isOpen) {
        NSLog(@"定位服务已经打开");
    }else {
        NSLog(@"定位服务未开启");

        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"你的定位服务未开启" message:@"请到setting开启定位服务" preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:nil]];
        [self presentViewController:alert animated:YES completion:nil];
        return;
    }

    // 判断应用是否获取定位授权
    NSInteger status = [CLLocationManager authorizationStatus];
    switch (status) {
        case 0:
            NSLog(@"kCLAuthorizationStatusNotDetermined--没有决定");//  用户从未选择过权限
            break;
        case 1:
            NSLog(@"kCLAuthorizationStatusRestricted--没有许可");// 无法使用定位服务,该状态用户无法改变
            break;
        case 2:
            NSLog(@"kCLAuthorizationStatusDenied--禁止使用");// 用户拒绝该应用使用定位服务,或是定位服务总开关处于关闭状态
            break;
        case 3:
            NSLog(@"kCLAuthorizationStatusAuthorizedAlways--始终允许");// 大致是用户同意程序在任意时候使用地理位置
            break;
        case 4:
            NSLog(@"kCLAuthorizationStatusAuthorizedWhenInUse--开启允许");// 大致是用户同意程序在可见时使用地理位置
            break;
        default:
            break;
    }

    // 2.初始化定位管家的对象,注意需要设置为全局变量,因为我们需要一直持有定位管家的对象,局部变量使用后即被销毁,在代理方法中,无法获得该对象及其属性,所以需要设置为全局变量
    [self locationManager];

    // 3.判断定位服务授权状态,设置定位权限:iOS8的新特性,可以实现代理方法获取授权范围。注意需要修改plist文件NSLocationAlwaysUsageDescription/NSLocationWhenInUseUsageDescription。
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
        // 判断授权状态,在授权未确定是获取授权,一旦确定即无法在程序中修改,只能在settings中对app做授权设置

        if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {// 判断系统版本 大于8.0以上的版本可以手动获取授权

            // 请求始终允许访问,包括进入后台后 对应info设置:NSLocationAlwaysUsageDescription
//            [self.locationManager requestAlwaysAuthorization];
            // 请求当app打开时允许访问 对应info设置:NSLocationWhenInUseUsageDescription
            [self.locationManager requestWhenInUseAuthorization];

            // 注意:修改plist文件
            // NSLocationAlwaysUsageDescription---我想在后台还访问您的位置
            // NSLocationWhenInUseUsageDescription---我想在我的app开启的时候使用您的位置,可以吗?
        }
    }else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {

        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"你没有给该应用的定位服务授权" message:@"请到setting设置定位服务授权" preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:nil]];
        [self presentViewController:alert animated:YES completion:nil];

        return;// 没有给予授权
    }

    // 4.设置定位服务的属性。
    [self.locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];

    // 设置定位刷新距离,可以直接是由上面的参数指定
    [self.locationManager setDistanceFilter:100];//移动距离大于distanceFilter就会定位,否则不会,避免频繁的定位,消耗电量

    // 5.开启定位,实现代理方法,获取定位信息
    [self.locationManager startUpdatingLocation];
//    [self.locationManager stopUpdatingLocation];// 获取定位数据后调用

    // 开始追踪导航方向,
    [self.locationManager startUpdatingHeading];
//    [self.locationManager stopUpdatingHeading];// 停止追踪导航方向

    // 开启区域追踪,需要传入一个追踪区域
    CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(39.0, 116.0);
    CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:coordinate radius:1000 identifier:@"找到你了"];
    [self.locationManager startMonitoringForRegion:region];
}
// 懒加载定位管家
- (CLLocationManager *)locationManager {

    if (!_locationManager) {

        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;// 设置定位服务的代理对象
    }

    return _locationManager;
}

#pragma mark CLLocationManagerDelegate
/**
 *  方法说明:当用户许可状态发生改变时,调用该方法
 *
 *  @param status:用户的许可状态
 *
 *  @return
 */
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    NSLog(@"认证状态改变 status:%d",status);
}

/**
 *  方法说明:执行定位后调用该方法
 *
 *  @param
 *
 *  @return
 */
- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray *)locations {

    // 停止定位(省电措施:只要不想用定位服务,或者获取定位信息后,就马上停止定位服务)
    [self.locationManager stopUpdatingLocation];

    // 1.取出位置对象(数组中可能会有多个位置对象,取出第一个是最精确的)
    CLLocation *loc = [locations firstObject];

    // 2.取出经纬度 coordinate:位置坐标  course:方向
    CLLocationCoordinate2D coordinate = loc.coordinate;
    CLLocationDegrees longitude = coordinate.longitude;
    CLLocationDegrees latitude = coordinate.latitude;

    // 3.CLLocations的常用属性和方法
    /*
     horizontalAccuracy,用来得到水平上的精确度,它的大小就是定位精度的半径,单位为米。获得的不是用户设置的精度  而是最终定位的精度,如果值为-1,则说明此定位不可信。
     course 方向: 0 ~ 359.9 , 0 代表正北
     speed 速度:m/s
     获取两个位置之间的距离
     - (CLLocationDistance)distanceFromLocation:(const CLLocation *)location
     */
    NSLog(@"经度:%f \n 纬度:%f", longitude, latitude);
    NSLog(@"方向:%f \n 海拔:%f",loc.course, loc.altitude);
    NSLog(@"水平定位精度%f  竖直定位精度%f",loc.horizontalAccuracy,loc.verticalAccuracy);
    NSLog(@"速度:%f",loc.speed);

    // 计算2个经纬度之间的直线距离
    CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:40 longitude:116];
    CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:41 longitude:116];

    // 计算2个经纬度之间的直线距离
    CGFloat distance = [self countLineDistance:loc1 withLocation:loc2];
    NSLog(@"%f",distance);
}

/**
 *  计算2个经纬度之间的直线距离
 */
- (double)countLineDistance:(CLLocation *)loc1 withLocation:(CLLocation *)loc2
{
    CLLocationDistance distance = [loc1 distanceFromLocation:loc2];

    return distance;
}

/**
 *  方法说明: 导航方向发生变化的时候执行此方法
 *
 *  @param  newHeading 方向: 0 ~ 359.9 , 0 代表正北
 *
 *  @return
 */
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
    NSLog(@"方向改变");
}

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    NSLog(@"进入到该区域");
}

- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region{

    NSLog(@"离开该区域");
}

@end

使用定位功能时,有几点需要我们注意:

  • 定位频率和定位精度并不应当越精确越好,需要视实际情况而定,因为越精确越耗性能,也就越费电。
  • 定位成功后会根据设置情况频繁调用-(void)locationManager:(CLLocationManager )manager didUpdateLocations:(NSArray )locations方法,使用完定位服务后如果不需要实时监控应该立即关闭定位服务以节省资源,所以我们需要在合适的时候停止定位。
  • -(void)locationManager:(CLLocationManager )manager didUpdateLocations:(NSArray )locations方法返回一组地理位置对象数组,每个元素一个CLLocation代表地理位置信息(包含经度、纬度、海报、行走速度等信息),之所以返回数组是因为有些时候一个位置点可能包含多个位置。

2. 地理编码和反地理编码

除了提供位置跟踪功能之外,在定位服务中还包含CLGeocoder类用于处理地理编码和逆地理编码功能。这个功能的实现主要是由CLGeocoder类提供的。CLGeocoder最主要的两个方法就是

  • -(void)geocodeAddressString:(NSString *)addressString completionHandler:(CLGeocodeCompletionHandler)completionHandler;// 根据给定的位置(通常是地名)确定地理坐标(经、纬度)。
  • -(void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler; // 根据地理坐标(经、纬度)确定位置信息(街道、门牌等)。

在上面两个方法的方法中,当地理编码或是反编码结束时,会回调CLGeocodeCompletionHandler,当中传递给我们两个参数,一个NSArray,一个NSError。NSError是编码或者反编码错误的详情,数组中则存放着我们地理编码或是反地理编码后获取的地标信息,为什么是数组呢,因为我们可能查询到多个地标,比如“帝都”代表的地标就有多个。在CoreLocation框架中,地标是一个CLPlacemark的实例对象。下面我们先来看一下CLPlacemark的常用属性:

属性 说明
@property (nonatomic, readonly, copy, nullable) CLLocation *location; 地理坐标
@property (nonatomic, readonly, copy, nullable) CLRegion *region; 地理范围
@property (nonatomic, readonly, copy, nullable) NSTimeZone *timeZone 地标所在时区
@property (nonatomic, readonly, copy, nullable) NSString *name; 地名
@property (nonatomic, readonly, copy, nullable) NSString *thoroughfare; 街道
@property (nonatomic, readonly, copy, nullable) NSString *subThoroughfare; 街道相关信息,例如门牌等
@property (nonatomic, readonly, copy, nullable) NSString *locality; 城市
@property (nonatomic, readonly, copy, nullable) NSString *subLocality; 城市相关信息,例如标志性建筑
@property (nonatomic, readonly, copy, nullable) NSString *administrativeArea;
@property (nonatomic, readonly, copy, nullable) NSString *subAdministrativeArea; 其他行政区域信息
@property (nonatomic, readonly, copy, nullable) NSString *postalCode; 邮编
@property (nonatomic, readonly, copy, nullable) NSString *ISOcountryCode; 国家编码
@property (nonatomic, readonly, copy, nullable) NSString *country; 国家
@property (nonatomic, readonly, copy, nullable) NSString *inlandWater; 水源、湖泊
@property (nonatomic, readonly, copy, nullable) NSString *ocean; 海洋
@property (nonatomic, readonly, copy, nullable) NSArray *areasOfInterest; 关联的或利益相关的地标
@property (nonatomic, readonly, copy) NSDictionary *addressDictionary; 地理的详细信息 包含上面所有的数据

示例代码

#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>

@interface ViewController ()

@property (nonatomic, strong)CLGeocoder *geocoder;//地理编码器

#pragma mark - 地理编码 根据地区名称查询所在的经纬度坐标
@property (strong, nonatomic) IBOutlet UITextField *addressField;//输入地区名称
@property (strong, nonatomic) IBOutlet UILabel *longitudeLabel;//显示地区的经度
@property (strong, nonatomic) IBOutlet UILabel *latitudeLabel;//显示地区的纬度
@property (strong, nonatomic) IBOutlet UILabel *detailAddressLabel;//显示地区的详细信息

#pragma mark - 反地理编码 根据经纬度获取对应的地区名
@property (strong, nonatomic) IBOutlet UITextField *reverseLongtitudeField;//查询地区的经度
@property (strong, nonatomic) IBOutlet UITextField *reverseLatitudeField;//查询地区的纬度
@property (strong, nonatomic) IBOutlet UILabel *reverseDetailAddressLabel;//查询的地区详细名称
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //初始化地理编码器
    if (!_geocoder) {
        _geocoder = [[CLGeocoder alloc] init];
    }
}

// 地理编码
- (IBAction)geocoder:(id)sender {

    //获取输入的城市名称
    NSString *address = self.addressField.text;
    if (address.length == 0) return;

    [self getCoordinateByAddress:address withBlock:^(CLPlacemark *pm) {

        // 设置经纬度
        self.latitudeLabel.text = [NSString stringWithFormat:@"%.2f", pm.location.coordinate.latitude];
        self.longitudeLabel.text = [NSString stringWithFormat:@"%.2f", pm.location.coordinate.longitude];

        // 设置具体地址
        self.detailAddressLabel.text = pm.name;

    } withfaild:^(NSError *error) {

        self.detailAddressLabel.text = @"你找的地址可能不存在,请重新输入";
        self.addressField.text = @"";
    }];
}

- (void)getCoordinateByAddress:(NSString *)address withBlock:(void(^)(CLPlacemark *pm))block withfaild:(void(^)( NSError *error))faild{

    [_geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {

        if (error) { // 有错误(地址乱输入)

            faild(error);
        } else { // 编码成功

            // 取出最前面的地址(数组中可能存在过河产讯到的地址)
            CLPlacemark *pm = [placemarks firstObject];
            // 回调数据
            block (pm);

            NSLog(@"总共找到%ld个地址", placemarks.count);
            //遍历数组,获取所有查找到的城市
            for (CLPlacemark *pm in placemarks) {

                NSLog(@"-----地址开始----");
                // 枚举编译出得所有的地理信息
                [pm.addressDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                    NSLog(@"%@:%@", key, obj);
                }];
                NSLog(@"-----地址结束----");
            }
        }
    }];
}

- (IBAction)reverseGeocoder:(id)sender {

    // 1.包装位置,将输入的字符串设置为地理坐标
    CLLocationDegrees latitude = [self.reverseLatitudeField.text doubleValue];
    CLLocationDegrees longitude = [self.reverseLongtitudeField.text doubleValue];
    CLLocation *loc = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];

    [self getAddressByLocation:loc withBlock:^(CLPlacemark *pm) {

        // 设置具体地址
        self.reverseDetailAddressLabel.text = [NSString stringWithFormat:@"%@ %@ %@ %@ %@",pm.country,pm.locality,pm.subLocality,pm.thoroughfare,pm.subThoroughfare];
    } withFaild:^(NSError *error) {

        self.reverseDetailAddressLabel.text = @"你找的地址可能只在火星有!!!";
    }];
}

- (void)getAddressByLocation:(CLLocation *)loc withBlock:(void(^)(CLPlacemark *pm))block withFaild:(void(^)(NSError *error))faild {

    // 2.反地理编码
    [_geocoder reverseGeocodeLocation:loc completionHandler:^(NSArray *placemarks, NSError *error) {
        if (error) { // 有错误(地址乱输入)

            faild (error);
        } else { // 编码成功

            // 取出最前面的地址
            CLPlacemark *pm = [placemarks firstObject];

            block (pm);

            NSLog(@"总共找到%ld个地址", placemarks.count);
            for (CLPlacemark *pm in placemarks) {

                NSLog(@"-----地址开始----");
                // 获取所有的地标信息
                [pm.addressDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                    NSLog(@"%@:%@", key, obj);
                }];

                NSLog(@"-----地址结束----");
            }
        }
    }];
}
@end
时间: 2024-12-17 15:25:21

定位服务的相关文章

iOS开发 定位服务与地图

概览 现在很多社交.电商.团购应用都引入了地图和定位功能,似乎地图功能不再是地图应用和导航应用所特有的.的确,有了地图和定位功能确实让我们的生活更加丰富多彩,极大的改变了我们的生活方式.例如你到了一个陌生的地方想要查找附近的酒店.超市等就可以打开软件搜索周边;类似的,还有很多团购软件可以根据你所在的位置自动为你推荐某些商品.总之,目前地图和定位功能已经大量引入到应用开发中.今天就和大家一起看一下iOS如何进行地图和定位开发. 定位 地图 定位 要实现地图.导航功能,往往需要先熟悉定位功能,在iO

简易的IOS位置定位服务

有时一些小的需求.事实上仅仅是须要得知当前IOS APP使用的地点.有些仅仅是想精确到城市级别,并不须要不论什么地图. 有了下面的简易实现: @interface MainViewController ()<CLLocationManagerDelegate> .... @end @implementation MainViewController - (void)InitLocation { //初始化定位服务管理对象 self.locationManager = [[CLLocationM

iOS定位服务与地图开发(1)---获取经纬度

定位服务是通过GPS等方式查找定位自己的位置的,再通过地图标注出来. 在iOS中定位服务和地图开发是使用两套API分别完成的. 1.定位服务: iOS系统提供3种不同定位途径: 1>WiFi定位:通过查询一个WiFi路由器的地理位置信息,iPhone.iPod Touch.iPad都可以采用. 2>蜂窝式移动电话基站定位:通过移动运营商基站定位 3>GPS卫星定位:通过3~4颗GPS卫星位置定位,最为准确,但是耗电量大 iOS不像Android系统在定位服务编程时可以指定采用哪种途径进行

Android 定位服务(Location-Based Services)

Android定位服务融合了GPS定位.移动通信.导航等多种技术,提供与空间位置相关的综合应用服务.近些年来,基于位置的服务发展更为迅速,涉及商务.医疗.工作和生活的各个方面,为用户提供定位.追踪和敏感区域警告等一系列服务. Android平台支持提供位置服务的API,在开发过程中主要使用LocationManager和LocationProviders对象. - LocationManager: 用来获取当前位置,追踪设备的移动路线,或设定敏感区域,在进入或离开敏感区域时设备会发出特定警报.

iOS 硬件授权检测:定位服务、通讯录、日历、提醒事项、照片、蓝牙共享、麦克风、相机等(转)

转载自:http://www.cocoachina.com/ios/20151214/14502.html iOS系统版本的不断升级的前提,伴随着用户使用设备的安全性提升,iOS系统对于App需要使用的硬件限制也越来越严格,App处理稍有不妥,轻则造成功能不可用用户还不知道,重则会造成App Crash. 当 用户在App启动时,看到弹出来的一条条“XXX 请求访问您的位置” “XXX 请求访问您的通讯录” “XXX 请求访问您的日历” “XXX 请求访问您的摄像头” 等一系列消息时,用户觉得不

在iOS8下使用CLLocationManager定位服务需要系统授权

最近在ios8.0使用CLLocationManager定位服务,发现老不能定位,查看设置菜单中的项也是处于未知状态.想起之前都有一个弹出框提示用户是否允许定位,这次一直没有出现了.原来ios8.0下的定位服务需要申请授权了. 具体代码如下: 1 if ([CLLocationManager locationServicesEnabled]) { 2 3 self.locationManager = [[CLLocationManager alloc] init]; 4 5 _locationM

手机定位服务将构建新一代网络(转来的)

导 语:试想一下,假如你的企业能够完全掌握客户的行踪——无论客户是逛杂货铺,还是在上班途中,甚至是出门遛狗,都尽在掌握,那么你能从中获得什么信息?假 如真的能够获取这些信息,你又希望借此向用户出售何种商品和服务呢?如果真的能够做到这一点,而且你的数据具备很高的相关性和实效性,那么用户又是否会出 于隐私的考虑而拒绝你的服务呢?这可不是科幻小说,而是一个新兴行业,它一由大批创业公司组成,而且借鉴了谷歌和诺基亚等科技巨头的经验,它们或许就能解 决上述问题. “点” 那 是一个多雪的冬季,在纽约SoHo

iOS定位服务编程详解

现在的移动设备很多都提供定位服务,使用iOS系统的iPhone.iPod Touch和iPad都可以提供位置服务,iOS设备能提供3种不同途径进行定位:Wifi, 蜂窝式移动电话基站, GPS卫星 iOS 不像Android系统在定位服务编程时,可以指定采用哪种途径进行定位.iOS的API把底层这些细节屏蔽掉了,开发人员和用户并不知道现在设备是采用 哪种方式进行定位的,iOS系统会根据设备的情况和周围的环境,采用一套最佳的解决方案.这个方案是这样的,如果能够接收GPS信息,那么设备优先采用 GP

iOS定位服务与地图开发(4)---显示地图

iOS 6之前,苹果使用的是谷歌地图,iOS 6之后,苹果使用了自己的地图(国内好像用的是高德地图),但是API编程接口与iOS 5相比没有太大变化. iOS 应用程序中使用Map Kit API开发地图应用程序,使用MKMapView类作为地图显示视图,其委托协议是MKMapViewDelegate. 1.显示地图: .h文件中代码 #import <MapKit/MapKit.h> @interface YXCViewController <MKMapViewDelegate>

iOS开发拓展篇—CoreLocation定位服务

一.简单说明 1.CLLocationManager CLLocationManager的常用操作和属性 开始用户定位- (void)startUpdatingLocation; 停止用户定位- (void) stopUpdatingLocation; 说明:当调用了startUpdatingLocation方法后,就开始不断地定位用户的位置,中途会频繁地调用代理的下面方法 - (void)locationManager:(CLLocationManager *)manager didUpdat