Core Location
来源:互联网 发布:周立功单片机培训 编辑:程序博客网 时间:2024/05/18 22:42
Core Location是iOS SDK中一个提供设备位置的框架。可以使用三种技术来获取位置:GPS、蜂窝或WiFi。在这些技术中,GPS最为精准,如果有GPS硬件,Core Location将优先使用它。如果设备没有GPS硬件(如WiFi iPad)或使用GPS获取当前位置时失败,Core Location将退而求其次,选择使用蜂窝或WiFi。
Core Location的大多数功能是由位置管理器(CLLocationManager)提供的,可以使用位置管理器来指定位置更新的频率和精度,以及开始和停止接收这些更新。
要使用位置管理器,必须首先将框架Core Location加入到项目中,再导入其接口文件:
#
import
<corelocation corelocation.h=
""
></corelocation>
CLLocationManager *locManager = [[CLLocationManager alloc] init];
locManager.delegate = self;
[locManager startUpdatingLocation];
//[locManager stopUpdatingLocation];
- (
void
)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
}
- (
void
)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
}
第一个方法处理定位成功,manager参数表示位置管理器实例;locations为一个数组,是位置变化的集合,它按照时间变化的顺序存放。如果想获得设备的当前位置,只需要访问数组的最后一个元素即可。集合中每个对象类型是CLLocation,它包含以下属性:
coordinate — 坐标。一个封装了经度和纬度的结构体。
altitude — 海拔高度。正数表示在海平面之上,而负数表示在海平面之下。
horizontalAccuracy — 位置的精度(半径)。位置精度通过一个圆表示,实际位置可能位于这个圆内的任何地方。这个圆是由coordinate(坐标)和horizontalAccuracy(半径)共同决定的,horizontalAccuracy的值越大,那么定义的圆就越大,因此位置精度就越低。如果horizontalAccuracy的值为负,则表明coordinate的值无效。
verticalAccuracy — 海拔高度的精度。为正值表示海拔高度的误差为对应的米数;为负表示altitude(海拔高度)的值无效。
speed — 速度。该属性是通过比较当前位置和前一个位置,并比较它们之间的时间差异和距离计算得到的。鉴于Core Location更新的频率,speed属性的值不是非常精确,除非移动速度变化很小
- (
void
)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *curLocation = [locations lastObject];
if
(curLocation.horizontalAccuracy >
0
)
{
NSLog(@
"当前位置:%.0f,%.0f +/- %.0f meters"
,curLocation.coordinate.longitude,
curLocation.coordinate.latitude,
curLocation.horizontalAccuracy);
}
if
(curLocation.verticalAccuracy >
0
)
{
NSLog(@
"当前海拔高度:%.0f +/- %.0f meters"
,curLocation.altitude,curLocation.verticalAccuracy);
}
}
应用程序开始跟踪用户的位置时,将在屏幕上显示一个是否允许定位的提示框。如果用户禁用定位服务,iOS不会禁止应用程序运行,但位置管理器将生成错误。
第二个方法处理这种定位失败,该方法的参数指出了失败的原因。如果用户禁止应用程序定位,error参数将为kCLErrorDenied;如果Core Location经过努力后无法确认位置,error参数将为kCLErrorLocationUnknown;如果没有可供获取位置的源,error参数将为kCLErrorNetwork。
通常,Core Location将在发生错误后继续尝试确定位置,但如果是用户禁止定位,它就不会这样做;在这种情况下,应使用方法stopUpdatingLocation停止位置管理器。
- (
void
)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
if
(error.code == kCLErrorLocationUnknown)
{
NSLog(@
"Currently unable to retrieve location."
);
}
else
if
(error.code == kCLErrorNetwork)
{
NSLog(@
"Network used to retrieve location is unavailable."
);
}
else
if
(error.code == kCLErrorDenied)
{
NSLog(@
"Permission to retrieve location is denied."
);
[manager stopUpdatingLocation];
}
}
extern
const
CLLocationAccuracy kCLLocationAccuracyBestForNavigation;
extern
const
CLLocationAccuracy kCLLocationAccuracyBest;
extern
const
CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;
extern
const
CLLocationAccuracy kCLLocationAccuracyHundredMeters;
extern
const
CLLocationAccuracy kCLLocationAccuracyKilometer;
extern
const
CLLocationAccuracy kCLLocationAccuracyThreeKilometers;
CLLocationManager *locManager = [[CLLocationManager alloc] init];
locManager.delegate = self;
locManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
locManager.distanceFilter =
200
;
[locManager startUpdatingLocation];
P.s. 定位要求的精度越高、属性distanceFilter的值越小,应用程序的耗电量就越大。
位置管理器有一个headingAvailable属性,它指出设备是否装备了磁性指南针。如果该属性为YES,就可以使用Core Location来获取航向(heading)信息。接收航向更新与接收位置更新极其相似,要开始接收航向更新,可指定位置管理器委托,设置属性headingFilter以指定要以什么样的频率(以航向变化的度数度量)接收更新,并对位置管理器调用方法startUpdatingHeading:
位置管理器委托协议定义了用于接收航向更新的方法。该协议有两个与航向相关的方法:
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager
{
return
YES;
}
- (
void
)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
}
第一个方法指定位置管理器是否向用户显示校准提示。该提示将自动旋转设备360°。由于指南针总是自我校准,因此这种提示仅在指南针读数剧烈波动时才有帮助。当设置为YES后,提示可能会分散用户的注意力,或影响用户的当前操作。
第二个方法的参数newHeading是一个CLHeading对象。CLHeading通过一组属性来提供航向读数:magneticHeading和trueHeading。这些值的单位为度,类型为CLLocationDirection,即双精度浮点数。这意味着:
如果航向为0.0,则前进方向为北;
如果航向为90.0,则前进方向为东;
如果航向为180.0,则前进方向为南;
如果航向为270.0,则前进方向为西。
CLHeading对象还包含属性headingAccuracy(精度)、timestamp(读数的测量时间)和description(这种描述更适合写入日志而不是显示给用户)。下面演示了利用这个方法处理航向更新:
- (
void
)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
if
(newHeading.headingAccuracy >=
0
)
{
NSString *headingDesc = [NSString stringWithFormat:@
"%.0f degrees (true), %.0f degrees (magnetic)"
,newHeading.trueHeading,newHeading.magneticHeading];
NSLog(@
"%@"
,headingDesc);
}
}
trueHeading和magneticHeading分别表示真实航向和磁性航向。如果位置服务被关闭了,GPS和wifi就只能获取magneticHeading(磁场航向)。只有打开位置服务,才能获取trueHeading(真实航向)。
下面的代码演示了,当存在一个确定了经纬度的地点,当前位置离这个地点的距离及正确航向:
#
import
"ViewController.h"
#define kDestLongitude
113.12
//精度
#define kDestLatitude
22.23
//纬度
#define kRad2Deg
57.2957795
// 180/π
#define kDeg2Rad
0.0174532925
// π/180
@interface
ViewController ()
@property
(strong, nonatomic) IBOutlet UILabel *lblMessage;
@property
(strong, nonatomic) IBOutlet UIImageView *imgView;
@property
(strong, nonatomic) CLLocationManager *locationManager;
@property
(strong, nonatomic) CLLocation *recentLocation;
-(
double
)headingToLocation:(CLLocationCoordinate2D)desired current:(CLLocationCoordinate2D)current;
@end
@implementation
ViewController
- (
void
)viewDidLoad
{
[
super
viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
self.locationManager.distanceFilter =
1609
;
//1英里≈1609米
[self.locationManager startUpdatingLocation];
if
([CLLocationManager headingAvailable])
{
self.locationManager.headingFilter =
10
;
//10°
[self.locationManager startUpdatingHeading];
}
}
/*
* According to Movable Type Scripts
*http://mathforum.org/library/drmath/view/55417.html
*
* Javascript:
*
* var y = Math.sin(dLon) * Math.cos(lat2);
* var x = Math.cos(lat1)*Math.sin(lat2) -
* Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
* var brng = Math.atan2(y, x).toDeg();
*/
-(
double
)headingToLocation:(CLLocationCoordinate2D)desired current:(CLLocationCoordinate2D)current
{
double
lat1 = current.latitude*kDeg2Rad;
double
lat2 = desired.latitude*kDeg2Rad;
double
lon1 = current.longitude;
double
lon2 = desired.longitude;
double
dlon = (lon2-lon1)*kDeg2Rad;
double
y = sin(dlon)*cos(lat2);
double
x = cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(dlon);
double
heading=atan2(y,x);
heading=heading*kRad2Deg;
heading=heading+
360.0
;
heading=fmod(heading,
360.0
);
return
heading;
}
//处理航向
- (
void
)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
if
(self.recentLocation!=nil && newHeading.headingAccuracy>=
0
)
{
CLLocation *destLocation = [[CLLocation alloc] initWithLatitude:kDestLatitude longitude:kDestLongitude];
double
course = [self headingToLocation:destLocation.coordinate current:self.recentLocation.coordinate];
double
delta = newHeading.trueHeading - course;
if
(abs(delta) <=
10
)
{
self.imgView.image = [UIImage imageNamed:@
"up_arrow.png"
];
}
else
{
if
(delta >
180
)
{
self.imgView.image = [UIImage imageNamed:@
"right_arrow.png"
];
}
else
if
(delta >
0
)
{
self.imgView.image = [UIImage imageNamed:@
"left_arrow.png"
];
}
else
if
(delta > -
180
)
{
self.imgView.image = [UIImage imageNamed:@
"right_arrow.png"
];
}
else
{
self.imgView.image = [UIImage imageNamed:@
"left_arrow.png"
];
}
}
self.imgView.hidden = NO;
}
else
{
self.imgView.hidden = YES;
}
}
//处理定位成功
- (
void
)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *curLocation = [locations lastObject];
if
(curLocation.horizontalAccuracy >=
0
)
{
self.recentLocation = curLocation;
CLLocation *destLocation = [[CLLocation alloc] initWithLatitude:kDestLatitude longitude:kDestLongitude];
CLLocationDistance distance = [destLocation distanceFromLocation:curLocation];
if
(distance<
500
)
{
[self.locationManager stopUpdatingLocation];
[self.locationManager stopUpdatingHeading];
self.lblMessage.text = @
"您已经到达目的地!"
;
}
else
{
self.lblMessage.text = [NSString stringWithFormat:@
"距离目的地还有%f米"
,distance];
}
}
}
//处理定位失败
- (
void
)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
if
(error.code == kCLErrorLocationUnknown)
{
NSLog(@
"Currently unable to retrieve location."
);
}
else
if
(error.code == kCLErrorNetwork)
{
NSLog(@
"Network used to retrieve location is unavailable."
);
}
else
if
(error.code == kCLErrorDenied)
{
NSLog(@
"Permission to retrieve location is denied."
);
[self.locationManager stopUpdatingLocation];
self.locationManager = nil;
}
}
- (
void
)didReceiveMemoryWarning
{
[
super
didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
最简单显示地图的代码:
注意:使用地图之前是需要引入MapKit框架的哦.
autoresizingMask是干什么用的呢(实际上,我看过后还是不懂)?
UIViewAutoresizingNone
这个常量如果被设置,视图将不进行自动尺寸调整。
UIViewAutoresizingFlexibleHeight
这个常量如果被设置,视图的高度将和父视图的高度一起成比例变化。否则,视图的高度将保持不变。
UIViewAutoresizingFlexibleWidth
这个常量如果被设置,视图的宽度将和父视图的宽度一起成比例变化。否则,视图的宽度将保持不变。
UIViewAutoresizingFlexibleLeftMargin
这个常量如果被设置,视图的左边界将随着父视图宽度的变化而按比例进行调整。否则,视图和其父视图的左边界的相对位置将保持不变。
UIViewAutoresizingFlexibleRightMargin
这个常量如果被设置,视图的右边界将随着父视图宽度的变化而按比例进行调整。否则,视图和其父视图的右边界的相对位置将保持不变。
UIViewAutoresizingFlexibleBottomMargin
这个常量如果被设置,视图的底边界将随着父视图高度的变化而按比例进行调整。否则,视图和其父视图的底边界的相对位置将保持不变。
UIViewAutoresizingFlexibleTopMargin
这个常量如果被设置,视图的上边界将随着父视图高度的变化而按比例进行调整。否则,视图和其父视图的上边界的相对位置将保持不变。
位置定位
为什么需要判断定位功能可不可用呢?下图可以看出为什么了.
打印信息:
2014-05-15 09:25:11.883 CoreLocation[17610:60b] <+37.78583400,-122.40641700> +/- 5.00m (speed -1.00 mps / course -1.00) @ 5/15/14, 9:25:11 AM China Standard Time
本人将这个代理定位的方式改写成了可以使用block的方式:
YXLocation.h
YXLocation.m
将经纬度转换为有意义的地址
打印信息如下:
2014-05-15 09:40:13.982 CoreLocation[2482:60b] 我在 中国北京市东城区东四街道东四朝阳门北小街2-1号
2014-05-15 09:40:13.986 CoreLocation[2482:60b] 国家代码 CN
2014-05-15 09:40:13.987 CoreLocation[2482:60b] 国家 中国
2014-05-15 09:40:13.988 CoreLocation[2482:60b] 邮政编码 (null)
2014-05-15 09:40:13.989 CoreLocation[2482:60b] administrativeArea 北京市
2014-05-15 09:40:13.991 CoreLocation[2482:60b] locality (null)
2014-05-15 09:40:13.992 CoreLocation[2482:60b] subLocality 东城区
2014-05-15 09:40:13.993 CoreLocation[2482:60b] subThoroughfare 2-1号
将有意义的地址转换为经纬度
打印信息:
2014-05-15 09:51:15.270 CoreLocation[2525:60b] 发现了 2 placemark(s).
2014-05-15 09:51:15.274 CoreLocation[2525:60b] 经度 = 116.425960
2014-05-15 09:51:15.275 CoreLocation[2525:60b] 纬度 = 39.931609
直接显示用户当前位置
- Core Location
- Core Location 简述
- 使用Core Location
- IOS Core Location
- Core Location之指南针
- Core Location Framework学习
- Core Location 简述
- Core Location定位
- iOS8 Core Location
- Core Location初心者
- iOS_mapKit与Core Location
- Core Location Framework学习
- Core Location的使用
- Cocoa框架-Core Location
- Core Location定位
- ios-Core Location框架
- Core Server Layer中Core Location学习心得
- IOS开发之Core Location
- 文章标题
- 如果点击事件截取,通过代理继续响应者链
- PostgreSQL & Oracle -1 OLTP "update/select based primary key" & insert
- 最短路径练习-POJ 1860 Currency Exchange
- Floyd传递闭包-POJ-3660-Cow Contest
- Core Location
- 网络原理,以及虚拟机相关配置
- POJ 1230 Pass-Muraille 贪心
- 【codevs3269】混合背包 背包DP裸题
- MAC安装MYSQL
- 比赛排名(猎豹笔试编程题)
- [Python]模拟键盘同时按下几个按键
- 面试小结一:关于操作系统的面试题整理
- iOS地图 MapKit框架