CoreLocation 是 iOS 中一个提供设备位置的框架。通过这个框架可以实现定位处理,获取位置数据。位置数据通常包括经度,纬度,海拔信息等。

准备

iOS8系统下使用定位服务必须在info.plist文件中添加 NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription 这两个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].countrymarks![0].city等属性即可获得CLLocation中的位置,可以通过回调函数等方法更新界面活进行其他操作。


Hydrogen
2.5k 声望73 粉丝

Write code for fun.