CoreLocation 是 iOS 中一个提供设备位置的框架。通过这个框架可以实现定位处理,获取位置数据。位置数据通常包括经度,纬度,海拔信息等。
准备
iOS8系统下使用定位服务必须在info.plist文件中添加 NSLocationAlwaysUsageDescription
和 NSLocationWhenInUseUsageDescription
这两个Key的值,将分别用于描述应用程序始终使用和使用期间使用定位的说明。
这两项内容只是对用户的提示,没有什么固定内容:
NSLocationAlwaysUsageDescription
类型String
应用程序始终使用定位服务NSLocationWhenInUseUsageDescription
类型String
使用应用程序期间,可以使用定位服务
随后在要使用的地方import CoreLocation
。
CLLocationManager
基本属性与方法
属性
location:
CLLocation
位置(以定位到的最新位置)desiredAccuracy:
CLLocationAccuray
位置精度
方法
func startUpdatingLocation() 开启更新位置
func stopUpdatingLocation() 停止更新位置
func startUpdatingHeading() 开启更新方向
func stopUdatingHeading() 停止更新方向
精度的六种选择
desiredAccuracy属性:
kCLLocationAccuracyBestForNavigation: CLLocationAccuracy
精度最高,一般用于导航kCLLocationAccuracyBest: CLLocationAccuracy
精度最佳kCLLocationAccuracyNearestTenMeters: CLLocationAccuracy
精确度10米内kCLLocationAccuracyHundredMeters: CLLocationAccuracy
精确度100米内kCLLocationAccuracyKilometer: CLLocationAccuracy
精确度1000米内kCLLocationAccuracyThreeKilometers: CLLocationAccuracy
精确度3000米内
对于管理器启动更新后,更新将不断传递给位置管理器委托,直到更新结束。我们无法直接控制位置管理器更新的频率,但可以用位置管理器的distanceFilter属性进行间接控制。在启动更新前设置属性distanceFilter,它指定设备移动多少米后才将另一个更新发给委托。定位要求的精度越高、属性distanceFilter的值越小,应用程序耗电量就越大。他的单位是米,我们可以直接使用整型数字来设置这个距离。
例如:
locationManager.distanceFilter = 200
获取授权
发出授权申请,设备会弹出提示,请求用户允许使用定位服务。代码如下:
locationManager.requestAlwaysAuthorization()
Delegate方法
通过didChangeAuthorizationStatus
代理方法,可以监听用户授权的改动。
func locationManager(_ manager: CLLocationManager,
didChangeAuthorizationStatus status: CLAuthorizationStatus){
if status == .NotDetermined || status == .Denied{
//允许使用定位服务
//开始启动定位更新服务
locationManager.startUpdatingLocation()
print("开始定位")
}
}
startUpdatingLocation
方法启动定位管理。
如果我们不需要更新定位时,可以通过stopUpdatingLocation
方法来关闭定位管理,这样可以节省电量。
locationManager.stopUpdatingLocation()
监听地点更新
对于委托类CLLocationManagerDelegate
最常用的方法是:
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation])
定位改变时委托执行这个方法,可以得到新位置,旧位置。location数组里会有前后位置的经度纬度坐标值。
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]){
var currlocation:CLLocation
//获取最新坐标
currlocation = locations.last as! CLLocation
}
CLLocation对象包含定位点的相关位置数据,主要有经度、纬度、海拔信息、可以通过属性和方法来获取。
CLLocation 相关知识
CLLocation类型是专门用来存放地点信息的类型,我们从CLLocationManager拿到的类型就是这种类型,下面我们来看看怎么使用它
CLLocation属性及方法
属性
coordinate: CLLocationCoordinate2D { get }
位置的纬度和经度altitude: CLLocationDistance { get }
位置海拔horizontalAccuracy: CLLocationAccuracy { get }
位置的水平精度verticalAccuracy: CLLocationAccuracy { get }
位置垂直精度speed: CLLocationSpeed { get }
位置的方向course: CLLocationDirection { get }
位置的速度
方法
func distanceFromLocation(_ location: CLLocation) -> CLLocationDistance
两个位置之间的距离。
关于方向
使用func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading)
可以获取到设备移动的方向。参数newHeading是一个CLHeading对象。CLHeading通过一组属性来提供航向读数:magneticHeading和trueHeading。这些值的单位为度。类型为CLLocationDirection,即双精度浮点数。这意味着:
如果航向为0.0,则前进方向为北
如果航向为90.0,则前进方向为东
如果航向为180.0,则前进方向为南
如果航向为270.0,则前进方向为西
magneticHeading和trueHeading分别表示磁性航向,和真实航向。如果位置服务被关闭了,GPS和WIFI就只能获取磁场航向。只有打开位置服务,才能获取真实航向。
需要注意,在使用代理前,需要开启更新方向:locationManager.startUpdatingHeading()
。
CLHeading 属性
属性名 | 描述 |
---|---|
magneticHeading | 位置的磁极方向 |
trueHeading | 位置的真实方向 |
headingAccuracy | 方向经度 |
timestamp | 时间戳 |
description | 获取方向数据 |
CLError
当定位失败时就会调用委托方法
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
//错误处理 当地位出错时调用
if let clerr = CLError(rawValue: error.code){
}
}
//CLError 是一个每枚举类型
public enum CLError : Int {
case LocationUnknown // location is currently unknown, but CL will keep trying
// 目前未知,请努力获取
case Denied // Access to location or ranging has been denied by the user
// 获取位置功能被拒绝使用
case Network // general, network-related error
//网络错误
case HeadingFailure // heading could not be determined
//获取的位置标题信息,不能确定
case RegionMonitoringDenied // Location region monitoring has been denied by the user
//位置区域已被用户监测
case RegionMonitoringFailure // A registered region cannot be monitored
//监测器不能注册
case RegionMonitoringSetupDelayed // CL could not immediately initialize region monitoring
//不能初始化检测器
case RegionMonitoringResponseDelayed // While events for this fence will be delivered, delivery will not occur immediately
//区域检测器响应延迟
case GeocodeFoundNoResult // A geocode request yielded no result
//地理编码无结果
case GeocodeFoundPartialResult // A geocode request yielded a partial result
//地理编码请求得到部分结果
case GeocodeCanceled // A geocode request was cancelled
//地理编码 请求被取消
case DeferredFailed // Deferred mode failed
//推迟模式失败
case DeferredNotUpdatingLocation // Deferred mode failed because location updates disabled or paused
//由于位置更新失败或者暂停,推迟模式失败
case DeferredAccuracyTooLow // Deferred mode not supported for the requested accuracy
//推迟模式不支持经度要求
case DeferredDistanceFiltered // Deferred mode does not support distance filters
//推迟模式无法支持距离滤波器
case DeferredCanceled // Deferred mode request canceled a previous request
//推迟模式被取消
case RangingUnavailable // Ranging cannot be performed
//无法进行测距
case RangingFailure // General ranging failure
//通用测距故障
}
以上就是常用的代理方法,其余可以参考文档。
地理信息反编码
通过Core Location类得到的地位信息都是以经度和纬度等表示的地理信息。一般都需要反编码城一个地址。
我们这里使用CLGeocoder来实现。
CLGeocoder提供了一个方便的异步方法进行地理信息反编码
// reverse geocode requests
public func reverseGeocodeLocation(location: CLLocation, completionHandler: CLGeocodeCompletionHandler)
首先实例化一个CLGeocoder对象`let geocoder = CLGeocoder()`,调用reverseGeocodeLocation方法。location参数即之前获得的CLLocation,完成闭包的两个参数分别是地点数组和错误码。
下面是一个简单的例子
let geocoder = CLGeocoder()
if let location = currentlocation{
geocoder.reverseGeocodeLocation(location, completionHandler: { (marks, error) -> Void in
if error == nil && marks?.count>0 {
var cityName = marks![0].locality!
let countryName = marks![0].country
//可调用回调函数
}
})
}
我们获得的 marks即CLPlacemark数组,这里我们说一下 CLPlacemark的常用属性。
CLPlacemark的常用属性
public var addressDictionary: [NSObject : AnyObject]? { get }
// address dictionary properties
public var name: String? { get } // eg. Apple Inc.
public var thoroughfare: String? { get } // street name, eg. Infinite Loop
public var subThoroughfare: String? { get } // eg. 1
public var locality: String? { get } // city, eg. Cupertino
public var subLocality: String? { get } // neighborhood, common name, eg. Mission District
public var administrativeArea: String? { get } // state, eg. CA
public var subAdministrativeArea: String? { get } // county, eg. Santa Clara
public var postalCode: String? { get } // zip code, eg. 95014
public var ISOcountryCode: String? { get } // eg. US
public var country: String? { get } // eg. United States
public var inlandWater: String? { get } // eg. Lake Tahoe
public var ocean: String? { get } // eg. Pacific Ocean
public var areasOfInterest: [String]? { get } // eg. Golden Gate Park
通过marks![0].country
、marks![0].city
等属性即可获得CLLocation中的位置,可以通过回调函数等方法更新界面活进行其他操作。