iOS开发者使用CoreLocation.framework框架进行定位非常简单CoreLocation框架的常用API主要有如下几个。
除此之外CoreLocation框架还涉及一个CLLocationCoordinate2D结构体变量该结构体变量包含经度、纬度两个值。其中CLLocation对象的coordinate属性就是一个CLLocationCoordinate2D结构体变量。
了解CoreLocation提供的这些API之后接下来即可通过这些API进行定位了。
使用CoreLocation.framework进行定位只要如下3步即可。
创建CLLocationManager对象该对象负责获取定位相关信息。并为该对象设置一些必要的属性。
为CLLocationManager指定delegate属性该属性值必须是一个实现CLLocationManagerDelegate协议的对象。实现CLLocationManagerDelegate协议时可根据需要实现协议中特定的方法。
调用CLLocationManager的startUpdatingLocation方法获取定位信息。定位结束时可调用stopUpdatingLocation方法结束获取定位信息。
注意
为了在iOS应用中使用CoreLocation.framework需要完成两件事情①为应用添加CoreLocation.framework框架②在需要使用定位服务及相关类的源文件中使用“#import <CoreLocation/CoreLocation.h>”导入CoreLocation.framework的头文件。本章绝大部分示例都使用了CoreLocation.framework因此都需要执行上面两步操作。
从上面介绍不难看出使用CoreLocation进行定位的关键就是CLLocationManager对象及其delegate对象。其中CLLocationManager负责获取定位信息而delegate则负责处理定位事件——通过这些事件即可获取设备所在位置。
CLLocationManager还提供了如下类方法来判断当前设备的定位相关服务状态。
除此之外在使用CLLocationManager开始定位之前还可为该对象设置如下属性。
接下来通过示例来示范使用CoreLocation定位iOS设备的位置。
创建一个Single View Application该项目包含一个应用程序委托类、一个视图控制器类和Main.storyboard界面设计文件。打开该项目的界面设计文件向其中添加5个文本框分别用于显示当前设备的经度、纬度、高度、速度和方向并在界面上添加一个UIButton按钮。
为了在程序中访问界面上的5个文本框需要将它们分别绑定到视图控制器类的longitudeTxt、latitudeTxt、altitudeTxt、speedTxt、courseTxt这5个IBOutlet属性为了让程序能响应按钮的点击事件还需要为按钮的“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对象设置了属性之后关键是将该视图控制器设置为CLLocationManager的delegate程序调用CLLocationManager的startUpdatingLocation方法开始获取定位数据。
由于程序指定该视图控制器作为CLLocationManager的delegate因此该视图控制器需要实现CLLocationManagerDelegate协议并实现该协议中定位相关的两个事件处理方法。当程序成功获取定位数据时将会激发delegate的locationManager:didUpdateLocations:方法因此上面视图控制器类实现了该方法并在该方法中获取最后一个定位数据CLLocation对象。
CLLocation对象中包含如下属性这些属性包含了定位相关信息。
每个iOS应用第一次使用定位功能时都会因为权限问题而弹出是否允许当前应用程序获取定位操作权限的提示框如图9.1所示。图9.1 询问用户是否允许该应用使用定位功能
单击“OK”按钮即可在Xcode控制器中看到“开始执行定位服务”的提示信息但可能依然看不到程序界面上有任何输出——此时我们可以通过模拟器来模拟设备的位置。
iOS模拟器本身并不能作为GPS接收机因此无法得到定位信息但为了方便程序员测试定位应用iOS模拟器可以模拟定位信息。
启动iOS模拟器之后即可通过iOS模拟器主菜单中的“调试”→“位置”来模拟iOS设备的位置该菜单如图9.2所示。
图9.2所示菜单支持如下几种位置信息。
如果选择“Freeway Driver”来模拟该设备携带者在高速公路中驾车则可以看到该应用显示如图9.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所示的结果。
————本文节选自《疯狂ios讲义下》
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。