疯狂ios讲义之使用CoreLocation定位(2)

9.2获取定位信息


iOS开发者使用CoreLocation.framework框架进行定位很是简单CoreLocation框架的经常使用API主要有以下几个。ios

CLLocationManager定位管理器类。git

CLLocationManagerdelegate该协议表明定位管理器的delegate协议。实现该协议的对象可负责处理CLLocationManager的定位事件。程序员

CLLocation该对象表明位置。该对象包含了当前设备的经度、纬度、高度、速度、路线等信息还包含了该定位信息的水平精确度、垂直精确度以及时间戳信息。app

CLHeading该对象表明设备的移动方向。框架

CLRegion该对象表明一个区域。通常程序不会直接使用该类而是使用它的两个子类即CLCircularRegion圆形区域和CLBeaconRegion蓝牙信号区。ide

除此以外CoreLocation框架还涉及一个CLLocationCoordinate2D结构体变量该结构体变量包含经度、纬度两个值。其中CLLocation对象的coordinate属性就是一个CLLocationCoordinate2D结构体变量。测试

了解CoreLocation提供的这些API以后接下来便可经过这些API进行定位了。atom

9.2.1 获取位置信息

使用CoreLocation.framework进行定位只要以下3步便可。spa

建立CLLocationManager对象该对象负责获取定位相关信息。并为该对象设置一些必要的属性。.net

CLLocationManager指定delegate属性该属性值必须是一个实现CLLocationManagerDelegate协议的对象。实现CLLocationManagerDelegate协议时可根据须要实现协议中特定的方法。

调用CLLocationManagerstartUpdatingLocation方法获取定位信息。定位结束时可调用stopUpdatingLocation方法结束获取定位信息。

注意    

    为了在iOS应用中使用CoreLocation.framework须要完成两件事情①为应用添加CoreLocation.framework框架②在须要使用定位服务及相关类的源文件中使用“#import <CoreLocation/CoreLocation.h>”导入CoreLocation.framework的头文件。本章绝大部分示例都使用了CoreLocation.framework所以都须要执行上面两步操做。

从上面介绍不难看出使用CoreLocation进行定位的关键就是CLLocationManager对象及其delegate对象。其中CLLocationManager负责获取定位信息而delegate则负责处理定位事件——经过这些事件便可获取设备所在位置。

CLLocationManager还提供了以下类方法来判断当前设备的定位相关服务状态。

+ locationServicesEnabled返回当前定位服务是否可用。

+ deferredLocationUpdatesAvailable返回延迟定位更新是否可用。

+ significantLocationChangeMonitoringAvailable返回重大位置改变监听是否可用。

+ headingAvailable返回该设备是否支持磁力计计算方向。

+ isRangingAvailable返回蓝牙信号范围服务是否可用。这是iOS 7新增的方法。

除此以外在使用CLLocationManager开始定位以前还可为该对象设置以下属性。

pausesLocationUpdatesAutomatically设置iOS设备是否可暂停定位来节省电池的电量。若是该属性设为“YES”则当iOS设备再也不须要定位数据时iOS设备能够自动暂停定位。

distanceFilter设置CLLocationManager的自动过滤距离。也就是说只有当设备在水平方向的位置改变超过该数值以米为单位指定的距离时才会生成一次位置改变的信号。

desiredAccuracy设置定位服务的精度。该属性值支持kCLLocationAccuracyBestForNavigation导航级的最佳精确度、kCLLocationAccuracyBest最佳精确度、kCLLocationAccuracy NearestTenMeters10米偏差、kCLLocationAccuracyHundredMeters百米偏差、kCLLocationAccuracyKilometer公里偏差、kCLLocationAccuracyThreeKilometers三公里偏差等常量值。固然也可直接指定一个浮点数做为定位服务容许的偏差。

activityType设置定位数据的用途。该属性支持CLActivityTypeOther定位数据做为普通用途、CLActivityTypeAutomotiveNavigation定位数据做为车辆导航使用、CLActivityTypeFitness定位数据做为步行导航使用和CLActivityTypeOtherNavigation定位数据做为其余导航使用这几个枚举值之一。

接下来经过示例来示范使用CoreLocation定位iOS设备的位置。

建立一个Single View Application该项目包含一个应用程序委托类、一个视图控制器类和Main.storyboard界面设计文件。打开该项目的界面设计文件向其中添加5个文本框分别用于显示当前设备的经度、纬度、高度、速度和方向并在界面上添加一个UIButton按钮。

为了在程序中访问界面上的5个文本框须要将它们分别绑定到视图控制器类的longitudeTxtlatitudeTxtaltitudeTxtspeedTxtcourseTxt5IBOutlet属性为了让程序能响应按钮的点击事件还须要为按钮的“Touch Up Inside”事件绑定bnTapped:事件处理方法。

下面是该视图控制器类的实现部分代码。

程序清单codes/09/9.2/LocationTest/LocationTest/FKViewController.m

@interface FKViewController () <CLLocationManagerDelegate>
@property (strong,nonatomic)CLLocationManager *locationManager;
@end
@implementation FKViewController
- (void)viewDidLoad
{  
    [super viewDidLoad];
    // 建立CLLocationManager对象
    self.locationManager = [[CLLocationManager alloc]init];
}
- (IBAction)bnTapped:(id)sender
{
    // 若是定位服务可用
    if([CLLocationManager locationServicesEnabled])
    {
        NSLog( @"开始执行定位服务" );
        // 设置定位精度最佳精度
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
        // 设置距离过滤器为50米表示每移动50米更新一次位置
        self.locationManager.distanceFilter = 50;
        // 将视图控制器自身设置为CLLocationManager的delegate
        // 所以该视图控制器须要实现CLLocationManagerDelegate协议
        self.locationManager.delegate = self;
        // 开始监听定位信息
        [self.locationManager startUpdatingLocation];
    }
    else
    {
        NSLog( @"没法使用定位服务" );
    }
}
// 成功获取定位数据后将会激发该方法
-(void)locationManager:(CLLocationManager *)manager
    didUpdateLocations:(NSArray *)locations
{
    // 获取最后一个定位数据
    CLLocation* location = [locations lastObject];
    // 依次获取CLLocation中封装的经度、纬度、高度、速度、方向等信息
    self.latitudeTxt.text = [NSString stringWithFormat:@"%g",
        location.coordinate.latitude];
    self.longitudeTxt.text = [NSString stringWithFormat:@"%g",
        location.coordinate.longitude];
    self.altitudeTxt.text = [NSString stringWithFormat:@"%g",
        location.altitude];
    self.speedTxt.text = [NSString stringWithFormat:@"%g",
        location.speed];
    self.courseTxt.text = [NSString stringWithFormat:@"%g",
        location.course];
}
// 定位失败时激发的方法
- (void)locationManager:(CLLocationManager *)manager
    didFailWithError:(NSError *)error
{
    NSLog(@"定位失败: %@",error);
}
@end

上面程序中的第1段粗体字代码为CLLocationManager对象设置了属性以后关键是将该视图控制器设置为CLLocationManagerdelegate程序调用CLLocationManagerstartUpdatingLocation方法开始获取定位数据。

因为程序指定该视图控制器做为CLLocationManagerdelegate所以该视图控制器须要实现CLLocationManagerDelegate协议并实现该协议中定位相关的两个事件处理方法。当程序成功获取定位数据时将会激发delegatelocationManager:didUpdateLocations:方法所以上面视图控制器类实现了该方法并在该方法中获取最后一个定位数据CLLocation对象。

CLLocation对象中包含以下属性这些属性包含了定位相关信息。

altitude该属性表示当前设备的海拔高度单位是米。

coordinate该属性返回一个CLLocationCoordinate2D结构体变量该结构体变量中包含经度、纬度信息。

course该属性表示当前设备前进的方向。该值为表示向北90°表示向东180°表示向南270°表示向西。

horizontalAccuracy该属性代表定位信息的水平精确度。将返回的坐标做为圆心并将水平精确度视为半径。真正的设备位置落在此圆内的某处。此圆越小位置就越精确此圆越大则位置越不精确。若是精确度为负值则代表测量精确度失败。

verticalAccuracy该属性代表定位信息的垂直精确度。也就是说iOS设备的实际高度在该定位信息的高度加或减该属性值的范围内。

timestamp该属性返回定位信息的返回时间。

speed该属性表示返回设备的移动速度单位是米/秒。实际上该属性适用于行车速度而不太适用于步行速度。

每一个 iOS 应用第一次使用定位功能时都会由于权限问题而弹出是否容许当前应用程序获取定位操做权限的提示框如图 9.1 所示。

110125_vcoW_262659.jpg

9.1 询问用户是否容许该应用使用定位功能

单击“OK”按钮便可在Xcode控制器中看到“开始执行定位服务”的提示信息但可能依然看不到程序界面上有任何输出——此时咱们能够经过模拟器来模拟设备的位置。

9.2.2使用iOS模拟器模拟位置

iOS模拟器自己并不能做为GPS接收机所以没法获得定位信息但为了方便程序员测试定位应用iOS模拟器能够模拟定位信息。

启动iOS模拟器以后便可经过iOS模拟器主菜单中的“调试”→“位置”来模拟iOS设备的位置该菜单如图9.2所示。

110204_32y4_262659.jpg

9.2所示菜单支持以下几种位置信息。

自定位置开发者能够自行输入位置的经度值、纬度值。

City Bicycle Ride模拟设备携带者在城市中骑车移动。

City Run模拟设备携带者在城市中跑动。

Freeway Drive模拟设备携带者在高速公路中驾车。

若是选择“Freeway Driver”来模拟该设备携带者在高速公路中驾车则能够看到该应用显示如图9.3所示。

110214_7Nk5_262659.jpg

9.2.3监控行车速度和行车距离

上一个示例是经过CLLocation对象来获取设备的移动速度和移动方向但这种移动速度属性适用于行车速度而不太适用于步行速度。若是但愿程序计算平均移动速度则只要不断地累计设备的移动距离和移动时间再用距离除以时间便可获得设备的平均移动速度。

下面经过一个示例来计算设备的平均移动速度。新建一个Single View Application打开该应用的Main.storyboard界面设计文件向该界面设计文件中拖入一个UITextView控件用于显示该设备的移动速度。为了在程序中访问该UITextView控件程序将它绑定到视图控制器的showView控件。

接下来修改视图控制器类在视图控制器类中经过设备的移动距离和移动时间来计算速度。下面是该视图控制器类的实现部分代码。

程序清单codes/09/9.2/SpeedMonitor/SpeedMonitor/FKViewController.m

#import "FKViewController.h"
#import <CoreLocation/CoreLocation.h>
@interface FKViewController () <CLLocationManagerDelegate>
@property (nonatomic , retain) CLLocationManager *locationManager;
@property (nonatomic , retain) CLLocation *prevLocation;
@property (nonatomic , assign) CGFloat sumDistance;
@property (nonatomic , assign) CGFloat sumTime;
@end
@implementation FKViewController
- (void) viewDidLoad
{
    [super viewDidLoad];
    // 建立CLLocationManager对象
    self.locationManager = [[CLLocationManager alloc] init];
}
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // 设置定位精度最佳精度
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    // 设置距离过滤器为50米表示每移动50米更新一次位置
    self.locationManager.distanceFilter = 50;
    // 将视图控制器自身设置为CLLocationManager的delegate
    // 所以该视图控制器须要实现CLLocationManagerDelegate协议
    self.locationManager.delegate = self;
    // 开始监听定位信息
    [self.locationManager startUpdatingLocation];
    NSLog(@"开始执行定位服务" );
}
// 定位失败时激发的方法
- (void)locationManager:(CLLocationManager *)manager
    didFailWithError:(NSError *)error
{
    NSLog(@"定位失败: %@",error);
}
// 成功获取定位数据后将会激发该方法
-(void)locationManager:(CLLocationManager *)manager
    didUpdateLocations:(NSArray *)locations
{
    // 获取最后一个定位数据
    CLLocation* newLocation = [locations lastObject];
    if(newLocation.horizontalAccuracy < kCLLocationAccuracyHundredMeters)
    {
        if(self.prevLocation)
        {
            // 计算本次定位数据与上次定位数据之间的时间差
            NSTimeInterval dTime = [newLocation.timestamp
                timeIntervalSinceDate:self.prevLocation.timestamp];
            // 累计行车时间
            self.sumTime += dTime;
            // 计算本次定位数据与上次定位数据之间的距离
            CGFloat distance = [newLocation
                distanceFromLocation:self.prevLocation];
            // 若是距离小于1米则忽略本次数据直接返回该方法
            if(distance < 1.0f)
            {
                return;
            }
            // 累加移动距离
            self.sumDistance += distance;
            // 计算移动速度将米/秒换算成公里/小时须要乘以3.6
            CGFloat speed = distance / dTime * 3.6;
            // 计算平均速度
            CGFloat avgSpeed = self.sumDistance / self.sumTime * 3.6;
            NSString * speedFeedback = [NSString stringWithFormat:
                @"当前速度为%g公里/小时平均速度为:%g公里/小时。合计移动:%g公里",
                speed , avgSpeed , self.sumDistance / 1000];
            self.showView.text = speedFeedback;
        }
        self.prevLocation = newLocation;
    }
}
@end

上面程序中的两行粗体字代码分别用于计算本次定位数据与上次定位数据之间的时间差、距离用此距离除以时间便可获得该设备的当前速度。除此以外该程序还定义了一个sumDistance属性来保存设备移动的总距离并定义了一个sumTime来保存设备移动的总时间用设备移动的总距离除以设备移动的总时间便可获取该设备移动的平均速度。

提示

iOS系统获取的先后两次定位数据的时间差以秒为单位先后两次定位数据之间的距离以米为单位所以直接用距离除以时间获得速度单位为米/秒。若是程序但愿以公里/小时做为速度单位则须要乘以3.6

编译、运行该程序并选择“Freeway Driver”来模拟设备携带者在高速公路中驾车将能够看到该应用显示如图9.4所示的结果。

110359_QxaG_262659.jpg

————本文节选自《疯狂ios讲义下》

110624_Bbvc_262659.jpg
相关文章
相关标签/搜索