须要驾驭斯威夫特的同伴能够翻一下事先的博文,供给理解Swift的同伙能够翻一下在此以前的博文

前言:
本章会利用OC和斯维夫特分别展开落到实处,必要精通斯维夫特的伙伴能够翻一下事先的博文

LBS和SoloMo(索罗门)

  • LBS:基于地方的服务,依据定位展现广大美味的吃食、景点等音信(全称:Location
    Bassed Service)
  • SoloMo:将地点社交、本地、移动化(全称:Soclal Local Moblle)
    • 社交化:在APP内投入一些社交成分,举行岗位分享等
    • 本地化:基于LBS周边的寻找等劳动
    • 移动化:基于3G\4G网络在移动APP上的劳务

获取地点信息

// 获取当前位置信息
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    // locations内的元素是按时间顺序排列,所以要获取最新的位置信息直接取locations数组内的最后一个元素即可(苹果官方文档注释)
    NSLog(@"%@", [locations lastObject]);
}

结果:维度、经度、海拔(负值表示近年来海拔无效)速度(负)航向(从0~359.9)
地点时间

图片 1

  • 基于取得的岗位音信计算用户行走方向,行走距离,偏移角度

    • coordinate:经纬度音讯
    • altitude:海拔
    • horizontalAccuracy:水平方向精度,值为负数时,表示无效
    • verticalAccuracy:判断海拔是或不是为负数,负数无效
    • course:航向(0~359.9)
    • floor:楼层(使用的楼层须要登记,不然不能够运用)
    • distanceFromLocation:计算2点之间的情理直线距离
OC:

        // 获取当前位置信息
        - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
    {
        /*
        * coordinate:经纬度信息
        * altitude:海拔
        * horizontalAccuracy:水平方向精确度,值如果小于0,代表位置数据无效
        * verticalAccuracy:判断海拔是否为负数,负数无效
        * floor:楼层,使用的楼层需要注册,否则无法使用
        * course:航向(0~359.9)(这里的0表示的是正北不是磁北)
        * distanceFromLocation:计算2各店之间物理直线距离
        */

        //  获取当前位置信息
        CLLocation *locationC = locations.lastObject;

        // 判断水平数据是否有效
        if (locationC.horizontalAccuracy < 0) { // 负数表示无效
            return;
        }
        // 计算行走方向(北偏东,东偏南,南偏西,西偏北)
        NSArray *courseAry = @[@"北偏东", @"东偏南", @"南偏西", @"西偏北"];
        // 将当前航向值/90度会得到对应的值(0,1,2,3)
        NSInteger i = locationC.course / 90;
        // 取出对应航向
        NSString *courseStr = courseAry[i];

        // 计算偏移角度
        NSInteger angle = (int)locationC.course % 90;
        // 判断是否为正方向
        // 对角度取余,为0表示正
        if (angle == 0) {

            // 截取字符串第一个字
            courseStr = [courseStr substringToIndex:1];
            // 拼接字符串
            courseStr = [@"正" stringByAppendingString:courseStr];
        }

        // 计算移动多少米
        CGFloat distance = [locationC distanceFromLocation:self.lastLocation];

        // 记录上次距离
        self.lastLocation = locationC;

        NSLog(@"向 %@ 方向走了 %lf 米偏移角度 %ld 度", courseStr, distance, angle);
    }

swift:

    // 当定位到位置后调用
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        // 获取用户当前最新位置
        let locationC = locations.last

        // 判断水平数据是否有效
        if locationC?.horizontalAccuracy < 0 { // 负数表示无效
            return
        }

        // 计算行走方向(北偏东,东偏南,南偏西,西偏北)
        let courseAry = ["北偏东", "东偏南", "南偏西", "西偏北"]
        // 将当前航向值/90度会得到相应的值(0,1,2,3)
        let i = Int((locationC?.course)! / 90)
        // 取出对应航向
        var courseStr = courseAry[i]

        // 计算偏移角度
        let angle = Int((locationC?.course)! % 90)
        // 判断是否为正方向
        // 对角度取余,为0就表示正
        if Int(angle) == 0 {
            // 截取字符串第一个字
            courseStr = (courseStr as NSString).substringToIndex(1)
        }

        // 确定移动距离
        let lastLoc = lastLocation ?? locationC
        let distance = locationC?.distanceFromLocation(lastLoc!)
        lastLocation = locationC

        // 拼接字符串
        print("向\(courseStr)方向走了\(distance!)米偏移角度\(angle)")
    }

区域监听

  • 区域监听正是依照必要钦点一块区域,当用户持设备进入或离开钦点区域,大家都能够监听到
  • iOS8上马,想要做区域监听,必须请求地点授权(因为区域监听原理正是拿到用户地方,然后判断地点是还是不是在设定的区域内,涉及到用户隐秘)

OC:

    - (CLLocationManager *)manager
{
    if (!_manager) {
        _manager = [[CLLocationManager alloc] init];
        _manager.delegate = self;

        // 请求用户授权区域监听
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
            [_manager requestAlwaysAuthorization];
        }
    }

    return _manager;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    // 判断区域监听是否可用
    if ([CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]]) {
        return;
    }

    // 创建一个区域
    // 确定圆心
    CLLocationCoordinate2D center = CLLocationCoordinate2DMake(21.23, 123.345);
    // 确定半径
    CLLocationDistance distance = 1000.0;
    // 因为监听区域有最大值,所以要判断下是否超过监听的最大值
    if (distance > self.manager.maximumRegionMonitoringDistance) {
        distance = self.manager.maximumRegionMonitoringDistance;
    }
    CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:distance identifier:@"123"];

    // 开始监听区域
    [self.manager startMonitoringForRegion:region];
}


// 进入区域时
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    NSLog(@"进入区域%@",region.identifier);
}

// 离开区域时
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
    NSLog(@"离开区域%@",region.identifier);
}

// 但外界调用请求某个指定区域的状态时
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
    if (state == CLRegionStateUnknown)
    {
        NSLog(@"未识别");
    }
    if (state == CLRegionStateInside) {
        NSLog(@"在区域内");
    }
    if (state == CLRegionStateOutside) {
        NSLog(@"在区域外");
    }
}

swift:

lazy var locationMgr : CLLocationManager = {

        let locationMgr = CLLocationManager()

        locationMgr.delegate = self

        // 记得设置相应的授权请求Key
        // 当前版本是8.0及以上
        if #available(iOS 8.0, *) {
            // 请求前后台定位授权
            locationMgr.requestAlwaysAuthorization()
        }

        return locationMgr

    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // 创建一个区域
        // 确定圆心
        let center = CLLocationCoordinate2DMake(21.23, 123.345)
        // 确定半径
        var distance : CLLocationDistance = 1000
        // 因为监听区域有最大值,索引先判断是否超过了监听区域的最大值
        if distance > locationMgr.maximumRegionMonitoringDistance {
            distance = locationMgr.maximumRegionMonitoringDistance
        }
        let region = CLCircularRegion(center: center, radius: distance, identifier: "123")

        // 判断取余监听是否可用
        if CLLocationManager.isMonitoringAvailableForClass(region.classForCoder) {
            // 开始监听区域
            locationMgr.startMonitoringForRegion(region)
        }


    }


    // 进入区域
    func locationManager(manager: CLLocationManager, didEnterRegion region: CLRegion) {
        print("进入监听区域")
    }

    // 离开区域
    func locationManager(manager: CLLocationManager, didExitRegion region: CLRegion) {
        print("离开监听区域")
    }

    // 区域状态改变
    func locationManager(manager: CLLocationManager, didDetermineState state: CLRegionState, forRegion region: CLRegion) {
        if state == .Unknown {
            print("未识别")
        }
        if state == .Inside {
            print("在区域内")
        }
        if state == .Outside {
            print("在区域外")
        }
    }
  • 注意:
    • 无法不请求用户定位授权
    • 动用前先判断区域监听是不是可用
    • 判定区域半径是或不是超越最大监听区域,假使超出最大监听区域范围,则无从监听成功

distanceFilter(距离过滤)和 desiredAccuracy(定位精确度)属性

  • distanceFilter(距离过滤):最新岗位距上次任务之间离开超越那么些值,就会告诉通过代理告诉外界
    • 暗中同意距离KCLDistanceFilterNone
      (值为-1,因为小于0,所以会平昔打字与印刷)
    • 单位:米
  • desiredAccuracy(定位精确度):定位精确度越高,定位时间就越长,也就越耗能
    • kCLLocationAccuracyBestForNavigation // 最适合导航
    • kCLLocationAccuracyBest // 最好的
    • kCLLocationAccuracyNearestTenMeters; // 附近10米
    • kCLLocationAccuracyHundredMeters; // 附近100米
    • kCLLocationAccuracyKilometer; // 附近1000米
    • kCLLocationAccuracyThreeKilometers; // 附近3000米

地理编码和反地理编码

  • 地理编码:指依据地质关键字,将其转换到对应的中纬度等音信
  • 反地理编码:指依照经纬度新闻,将其转换来对应的省市区等音信
  • CLPlacemark(地球表面对象)
    • location:CLLocation类型,地点对象的消息,蕴涵经纬度,海拔等
    • region:CLRegion类型,地球表面对象对应区域
    • addressDictionary:NSDictionary类型,存放省市,街道等音信
    • name:NSString类型,地址全称
    • thoroughfare:NSString类型,街道名称
    • locality:NSString类型,城市名称
    • administrativeArea:NSString类型,省名称
    • country:NSString类型,国家名称
  • 注意
    • 非得联网
    • 偶尔反地理编码时会找不到相应音信,必要尝试更换经纬度

OC:

CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    // 地理编码
    [geocoder geocodeAddressString:@"福建省厦门市" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {

        CLPlacemark *placeM = [placemarks lastObject];

        NSLog(@"维度:%@ -- 经度:%@", @(placeM.location.coordinate.latitude).stringValue, @(placeM.location.coordinate.longitude).stringValue);
    }];

    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    // 反地理编码
    CLLocationDegrees latitude = 24.490474;
    CLLocationDegrees longitude = 118.11022;
    CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        NSLog(@"地址:%@", [placemarks firstObject].name);
    }];

swift:

let geocoder = CLGeocoder()
        // 地理编码
        geocoder.geocodeAddressString("福建省厦门市") { (placemarks, error) in

            let placeM = placemarks?.last

            print("维度\(placeM?.location?.coordinate.latitude) -- 经度\(placeM?.location?.coordinate.longitude)")
        }

        // 反地理编码
        let latitude : CLLocationDegrees = 24.490474
        let longitude : CLLocationDegrees = 118.11022
        let location = CLLocation(latitude: latitude, longitude: longitude)

        geocoder.reverseGeocodeLocation(location) { (placemarks, error) in
            print("地址:\(placemarks?.first?.name)")
        }

    }

先到这,近期太忙,过二日找个时间依据定位做个小项目再享受出去
小品种地址

iOS8后头定位

  • 从iOS8发端,苹果尤其进步了对用户隐衷的保卫安全,当APP想范围用户隐衷音讯的时候,系统不再自动弹出对话框让用户授权,为了能让系统活动弹出用户授权界面,需求进行上边安装

    • 缓解方案:调用iOS8的API,主动请求用户授权
<!-- -->

    // 注意:根据官方文档的解释,在使用下面2个方法的时候,如果不在info.plist中配置NSLocationWhenInUseUsageDescription这个key,那么方法都不会生效
    // 请求前台定位授权
        - (void)requestWhenInUseAuthorization

    // 注意:根据官方文档的解释,在使用下面2个方法的时候,如果不在info.plist中配置`NSLocationAlwaysUsageDescription`这个key,那么方法都不会生效
    // 请求前后台定位授权
        - (void)requestAlwaysAuthorization

OC:

- (CLLocationManager *)manager
{
    if (_manager == nil) {
        _manager = [[CLLocationManager alloc] init];

        _manager.delegate = self;

        // 需要注意的是,必须在info.plist文件中配置’NSLocationWhenInUseUsageDescription‘这个key,否则下面方法无效(官方注释有提到)
        // 请求前台授权
        [_manager requestWhenInUseAuthorization];
        // 请求前后台授权
//        [_manager requestAlwaysAuthorization];
    }

    return _manager;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self.manager startUpdatingLocation];
}

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    NSLog(@"定位到了");

    [self.manager stopUpdatingLocation];
}

swift:

class ViewController: UIViewController {

    lazy var locationMgr : CLLocationManager = {

        let locationMgr = CLLocationManager()

        locationMgr.delegate = self

        // 记得设置相应的授权请求Key
        // 请求前台定位授权
        locationMgr.requestWhenInUseAuthorization()
        // 请求前后台定位授权
        locationMgr.requestAlwaysAuthorization()

        return locationMgr

    }()

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

        // 开启定位
        locationMgr.startUpdatingLocation()
    }


}

//MARK: - CLLocationManager代理
extension ViewController : CLLocationManagerDelegate {

    // 当定位到位置后调用
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        print("定位到了")

        manager.stopUpdatingLocation()
    }
}

distanceFilter(距离过滤)和 desiredAccuracy(定位精确度)属性

  • distanceFilter(距离过滤):最新岗位距上次岗位之间离开当先那么些值,就会报告通过代理告诉外界
    • 暗中同意距离KCLDistanceFilterNone
      (值为-1,因为小于0,所以会向来打字与印刷)
    • 单位:米
  • desiredAccuracy(定位精确度):定位精确度越高,定位时间就越长,也就越功耗
    • kCLLocationAccuracyBestForNavigation // 最契合导航
    • kCLLocationAccuracyBest // 最好的
    • kCLLocationAccuracyNearestTenMeters; // 附近10米
    • kCLLocationAccuracyHundredMeters; // 附近100米
    • kCLLocationAccuracyKilometer; // 附近1000米
    • kCLLocationAccuracyThreeKilometers; // 附近3000米

CoreLocation介绍

  • 固定已经能够说是现在APP的主流,没有永恒效率的APP都不佳意思和大家会合,作为APP的首要组成都部队分,其实采纳也十分简单,本章就苹果的CoreLocation框架举行简单分析和使用
  • CoreLocation主要功用
    • 地理定位:获取用户之所以在区域,获得相应的中纬度或许海拔等一些地理消息
    • 地理编码:依照详细的地点转换为经纬度新闻
    • 反地理编码:依据经纬度音信转换来具体地址
    • 区域监听:钦点一个区域,当用户进入或然离开这一个区域,大家都可以监听到对应消息
    • 相似MapKit和联合利用,因为Mapkit正是依据CoreLocation进行付出的,所以MapKit能展开稳定也能显示地图,以往会就MapKit实行详解

iOS8事先一定

  • 在XCode5以前我们需求运用的框架修必要手动导入(那边使用的是XCode7.3,有争论的请举办相应调整)
  • CoreLocation框架的主头文件#import
    <CoreLocation/CoreLocation.h>
  • 定点前须要先拿走CLLocationManager对象
  • 从iOS6上马,想要获取用户的心事(通信录、日历、相机、定位、相册等),系统会自行弹框请求授权
  • 在iOS8.0事先,为了增长用户点击允许授权的机率,平日会在info.plist中配备相应的key(Privacy –
    Location Usage Description)用来证实定位目标

OC:

// 为了全局只使用一个位置管理者,我们先对CLLocationManager进行懒加载
- (CLLocationManager *)locationM {
    if (_locationM == nil) {

        // 创建位置管理者
        _locationM = [[CLLocationManager alloc] init];

        // 设置代理
        _locationM.delegate = self;

    }
    return _locationM;
}

// 在按钮点击事件中开启定位服务
    // start:开启服务 stop:关闭服务
    // 一旦调用这个方法,就会不断的调用用户信息(因为distanceFilter属性的默认值为-1)
    // 基本定位(基于Wifi/GPS)
    [self.locationM startUpdatingLocation];


// 这个方法是用来监听重大位置改变(因为基站与基站之间相距大所以这个方法会通过基站进行定位,前提是有电话模块的支持)
//    [self.locationM startMonitoringSignificantLocationChanges];

// 先遵守CLLocationManagerDelegate协议,实现下面代理方法

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {

    NSLog(@"已定位到");

// 定位是非常频繁的,所以获取到用户信息后,最好马上关闭停止定位,以达到省电效果,在适当的时候再重新打开定位
    [manager stopUpdatingLocation];
    self.locationM = nil;

}

Swift:

// MARK:- 懒加载
    private lazy var locationM : CLLocationManager = {
        // 创建位置管理者
        let locationM = CLLocationManager()

        // 设置代理
        locationM.delegate = self

        return locationM

    }()

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

        // 使用位置管理者获取用户位置信息
        // 根据苹果的习惯,一般方法命中带ing(现在进行时),说明一旦执行这个方法,系统就会不断的调用这个方法
        // 默认情况下只会在前台进行定位,如果在后台也想要获取用户的位置,需要开启后台模式 location updates
        locationM.startUpdatingLocation()

    }

// MARK:- CLLocationManagerDelegate
extension ViewController : CLLocationManagerDelegate {

    // manager :  位置管理者
    // locations : 位置数组
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print("已定位到")
        //  关闭定位
        manager.stopUpdatingLocation()
    }

后台继续一向

只要想要在后台继续展开固定,须要开辟后台的一贯形式

图片 2

拓展:

  • 规范的定点服务(基于GPS/Wifi/基站的定点服务)
    • 先后被完全关闭后就无法再取得地方新闻
  • 肯定地方变动一定服务(基于基站的一直服务,设备必须有电话模块协助)
    • 当APP被全然关闭后,也足以接过到岗位布告,并且让APP进入后台处理
    • 定位精度相对刘和平规定点服务较低,耗能量小,更新的成效根据当下职责紧邻的基站密度决定

startMonitoringSignificantLocationChanges(重庆大学职务变动监听)

  • 当地方产生较大变化后会调用这几个服务(基于基站定位,所以供给求有电话模块)
    • 优势:当APP被完全关闭后,也得以接到到岗位通告,并且让APP进入后台处理,耗能量小
    • 逆风局:定位精度相对于专业定点服务较低,更新的频率依照方今地方紧邻的基站密度决定

永恒适配

  • 诚如大家适配版本都会咬定当前设备的版本,然后再进行对应的适配操作,那边就介绍另一种比较不难的适配格局
    • 通过respondsToSelector:方法来判定方式是或不是可响应,能够的话再实施

OC:

if ([_manager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {

      // 需要注意的是,必须在info.plist文件中配置’NSLocationWhenInUseUsageDescription‘这个key,否则下面方法无效(官方注释有提到)
      // 请求前台授权
      [_manager requestWhenInUseAuthorization];
}

if ([_manager respondsToSelector:@selector(requestAlwaysAuthorization)]) {

     // 请求前后台授权(无论是否开启后台模式都可以获取位置信息,并且不会出现蓝条提示)
      [_manager requestAlwaysAuthorization];
}

swift:

// 记得设置相应的授权请求Key
        // 根据当前系统版本适配
        // 当前版本是8.0及以上
        if #available(iOS 8.0, *) {
            // 请求前台定位授权
            locationMgr.requestWhenInUseAuthorization()
        }
        if #available(iOS 8.0, *) {
            // 请求前后台定位授权
            locationMgr.requestAlwaysAuthorization()
        }
  • iOS9定位变化
    • 前台定位于iOS8无变化
      • 后台定位
        • 办法一:在前台定位授权基础上,勾选后台格局location
          updates之后,要求十一分设置属性allowsBackgroundLocationUpdates
          = YES
        • 方式二:直接呼吁前后台定位授权,设置属性allowsBackgroundLocationUpdates
          = YES,开启后台情势

赢得地点音讯

// 获取当前位置信息
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    // locations内的元素是按时间顺序排列,所以要获取最新的位置信息直接取locations数组内的最后一个元素即可(苹果官方文档注释)
    NSLog(@"%@", [locations lastObject]);
}

结果:维度、经度、海拔(负值表示近日海拔无效)速度(负)航向(从0~359.9)
地方时间

图片 3

  • 依照取得的地方音讯总括用户行走方向,行走距离,偏移角度

    • coordinate:经纬度新闻
    • altitude:海拔
    • horizontalAccuracy:水平方向精度,值为负数时,表示无效
    • verticalAccuracy:判断海拔是或不是为负数,负数无效
    • course:航向(0~359.9)
    • floor:楼层(使用的楼面要求登记,不然不可能利用)
    • distanceFromLocation:总结2点中间的物理直线距离
OC:

        // 获取当前位置信息
        - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
    {
        /*
        * coordinate:经纬度信息
        * altitude:海拔
        * horizontalAccuracy:水平方向精确度,值如果小于0,代表位置数据无效
        * verticalAccuracy:判断海拔是否为负数,负数无效
        * floor:楼层,使用的楼层需要注册,否则无法使用
        * course:航向(0~359.9)(这里的0表示的是正北不是磁北)
        * distanceFromLocation:计算2各店之间物理直线距离
        */

        //  获取当前位置信息
        CLLocation *locationC = locations.lastObject;

        // 判断水平数据是否有效
        if (locationC.horizontalAccuracy < 0) { // 负数表示无效
            return;
        }
        // 计算行走方向(北偏东,东偏南,南偏西,西偏北)
        NSArray *courseAry = @[@"北偏东", @"东偏南", @"南偏西", @"西偏北"];
        // 将当前航向值/90度会得到对应的值(0,1,2,3)
        NSInteger i = locationC.course / 90;
        // 取出对应航向
        NSString *courseStr = courseAry[i];

        // 计算偏移角度
        NSInteger angle = (int)locationC.course % 90;
        // 判断是否为正方向
        // 对角度取余,为0表示正
        if (angle == 0) {

            // 截取字符串第一个字
            courseStr = [courseStr substringToIndex:1];
            // 拼接字符串
            courseStr = [@"正" stringByAppendingString:courseStr];
        }

        // 计算移动多少米
        CGFloat distance = [locationC distanceFromLocation:self.lastLocation];

        // 记录上次距离
        self.lastLocation = locationC;

        NSLog(@"向 %@ 方向走了 %lf 米偏移角度 %ld 度", courseStr, distance, angle);
    }

swift:

    // 当定位到位置后调用
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        // 获取用户当前最新位置
        let locationC = locations.last

        // 判断水平数据是否有效
        if locationC?.horizontalAccuracy < 0 { // 负数表示无效
            return
        }

        // 计算行走方向(北偏东,东偏南,南偏西,西偏北)
        let courseAry = ["北偏东", "东偏南", "南偏西", "西偏北"]
        // 将当前航向值/90度会得到相应的值(0,1,2,3)
        let i = Int((locationC?.course)! / 90)
        // 取出对应航向
        var courseStr = courseAry[i]

        // 计算偏移角度
        let angle = Int((locationC?.course)! % 90)
        // 判断是否为正方向
        // 对角度取余,为0就表示正
        if Int(angle) == 0 {
            // 截取字符串第一个字
            courseStr = (courseStr as NSString).substringToIndex(1)
        }

        // 确定移动距离
        let lastLoc = lastLocation ?? locationC
        let distance = locationC?.distanceFromLocation(lastLoc!)
        lastLocation = locationC

        // 拼接字符串
        print("向\(courseStr)方向走了\(distance!)米偏移角度\(angle)")
    }

LBS和SoloMo(索罗门)

  • LBS:基于地方的服务,依据定位突显广大美味的食品、景点等音信(全称:Location
    Bassed 瑟维斯)
  • SoloMo:将地点社交、本地、移动化(全称:Soclal Local Moblle)
    • 社交化:在APP内进入一些交际成分,实行岗位分享等
    • 本地化:基于LBS周边的搜寻等劳动
    • 移动化:基于3G\4G互联网在移动APP上的劳务

CoreLocation介绍

  • 定位已经能够说是现行反革命APP的主流,没有一向成效的APP都不佳意思和豪门照面,作为APP的第③组成都部队分,其实使用也万分不难,本章就苹果的CoreLocation框架进行简要解析和选拔
  • CoreLocation首要意义
    • 地理定位:获取用户之所以在区域,获得相应的经纬度也许海拔等局部地理消息
    • 地理编码:根据详细的地址转换为经纬度音信
    • 反地理编码:依据经纬度新闻转换到具体地址
    • 区域监听:钦命三个区域,当用户进入只怕离开这么些区域,大家都足以监听到对应新闻
    • 诚如MapKit和一起使用,因为Mapkit正是根据CoreLocation举办付出的,所以MapKit能开始展览定位也能显得地图,以往会就MapKit举办详解

区域监听

  • 区域监听便是依据要求钦定一块区域,当用户持设备进入或离开钦点区域,我们都能够监听到
  • iOS8上马,想要做区域监听,必须请求地方授权(因为区域监听原理正是收获用户地点,然后判断地方是否在设定的区域内,涉及到用户隐秘)

OC:

    - (CLLocationManager *)manager
{
    if (!_manager) {
        _manager = [[CLLocationManager alloc] init];
        _manager.delegate = self;

        // 请求用户授权区域监听
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
            [_manager requestAlwaysAuthorization];
        }
    }

    return _manager;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    // 判断区域监听是否可用
    if ([CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]]) {
        return;
    }

    // 创建一个区域
    // 确定圆心
    CLLocationCoordinate2D center = CLLocationCoordinate2DMake(21.23, 123.345);
    // 确定半径
    CLLocationDistance distance = 1000.0;
    // 因为监听区域有最大值,所以要判断下是否超过监听的最大值
    if (distance > self.manager.maximumRegionMonitoringDistance) {
        distance = self.manager.maximumRegionMonitoringDistance;
    }
    CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:distance identifier:@"123"];

    // 开始监听区域
    [self.manager startMonitoringForRegion:region];
}


// 进入区域时
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    NSLog(@"进入区域%@",region.identifier);
}

// 离开区域时
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
    NSLog(@"离开区域%@",region.identifier);
}

// 但外界调用请求某个指定区域的状态时
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
    if (state == CLRegionStateUnknown)
    {
        NSLog(@"未识别");
    }
    if (state == CLRegionStateInside) {
        NSLog(@"在区域内");
    }
    if (state == CLRegionStateOutside) {
        NSLog(@"在区域外");
    }
}

swift:

lazy var locationMgr : CLLocationManager = {

        let locationMgr = CLLocationManager()

        locationMgr.delegate = self

        // 记得设置相应的授权请求Key
        // 当前版本是8.0及以上
        if #available(iOS 8.0, *) {
            // 请求前后台定位授权
            locationMgr.requestAlwaysAuthorization()
        }

        return locationMgr

    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // 创建一个区域
        // 确定圆心
        let center = CLLocationCoordinate2DMake(21.23, 123.345)
        // 确定半径
        var distance : CLLocationDistance = 1000
        // 因为监听区域有最大值,索引先判断是否超过了监听区域的最大值
        if distance > locationMgr.maximumRegionMonitoringDistance {
            distance = locationMgr.maximumRegionMonitoringDistance
        }
        let region = CLCircularRegion(center: center, radius: distance, identifier: "123")

        // 判断取余监听是否可用
        if CLLocationManager.isMonitoringAvailableForClass(region.classForCoder) {
            // 开始监听区域
            locationMgr.startMonitoringForRegion(region)
        }


    }


    // 进入区域
    func locationManager(manager: CLLocationManager, didEnterRegion region: CLRegion) {
        print("进入监听区域")
    }

    // 离开区域
    func locationManager(manager: CLLocationManager, didExitRegion region: CLRegion) {
        print("离开监听区域")
    }

    // 区域状态改变
    func locationManager(manager: CLLocationManager, didDetermineState state: CLRegionState, forRegion region: CLRegion) {
        if state == .Unknown {
            print("未识别")
        }
        if state == .Inside {
            print("在区域内")
        }
        if state == .Outside {
            print("在区域外")
        }
    }
  • 注意:
    • 务必请求用户定位授权
    • 选取前先判断区域监听是还是不是可用
    • 认清区域半径是或不是当先最大监听区域,假若抢先最大监听区域限制,则不可能监听成功

后台继续稳定

假使想要在后台继续举办稳定,必要开辟后台的稳定情势

图片 4

拓展:

  • 行业内部的原则性服务(基于GPS/Wifi/基站的固化服务)
    • 先后被统统关闭后就不能够再拿走地方新闻
  • 明显地点变动一定服务(基于基站的稳定服务,设备必须有电话模块援助)
    • 当APP被全然关闭后,也足以收到到岗位文告,并且让APP进入后台处理
    • 定位精度相对任宝茹规定点服务较低,功耗量小,更新的频率依据当前岗位紧邻的基站密度决定

iOS8事先一定

  • 在XCode5此前大家必要动用的框架修供给手动导入(这边使用的是XCode7.3,有争论的请举办对应调整)
  • CoreLocation框架的主头文件#import
    <CoreLocation/CoreLocation.h>
  • 一定前须求先取得CLLocationManager对象
  • 从iOS6发端,想要获取用户的心曲(通信录、日历、相机、定位、相册等),系统会自行弹框请求授权
  • 在iOS8.0事先,为了增强用户点击允许授权的机率,经常会在info.plist中配备相应的key(Privacy –
    Location Usage Description)用来验证定位指标

OC:

// 为了全局只使用一个位置管理者,我们先对CLLocationManager进行懒加载
- (CLLocationManager *)locationM {
    if (_locationM == nil) {

        // 创建位置管理者
        _locationM = [[CLLocationManager alloc] init];

        // 设置代理
        _locationM.delegate = self;

    }
    return _locationM;
}

// 在按钮点击事件中开启定位服务
    // start:开启服务 stop:关闭服务
    // 一旦调用这个方法,就会不断的调用用户信息(因为distanceFilter属性的默认值为-1)
    // 基本定位(基于Wifi/GPS)
    [self.locationM startUpdatingLocation];


// 这个方法是用来监听重大位置改变(因为基站与基站之间相距大所以这个方法会通过基站进行定位,前提是有电话模块的支持)
//    [self.locationM startMonitoringSignificantLocationChanges];

// 先遵守CLLocationManagerDelegate协议,实现下面代理方法

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {

    NSLog(@"已定位到");

// 定位是非常频繁的,所以获取到用户信息后,最好马上关闭停止定位,以达到省电效果,在适当的时候再重新打开定位
    [manager stopUpdatingLocation];
    self.locationM = nil;

}

Swift:

// MARK:- 懒加载
    private lazy var locationM : CLLocationManager = {
        // 创建位置管理者
        let locationM = CLLocationManager()

        // 设置代理
        locationM.delegate = self

        return locationM

    }()

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

        // 使用位置管理者获取用户位置信息
        // 根据苹果的习惯,一般方法命中带ing(现在进行时),说明一旦执行这个方法,系统就会不断的调用这个方法
        // 默认情况下只会在前台进行定位,如果在后台也想要获取用户的位置,需要开启后台模式 location updates
        locationM.startUpdatingLocation()

    }

// MARK:- CLLocationManagerDelegate
extension ViewController : CLLocationManagerDelegate {

    // manager :  位置管理者
    // locations : 位置数组
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print("已定位到")
        //  关闭定位
        manager.stopUpdatingLocation()
    }

原则性服务未开启也许被用户真正拒绝情状下的情景处理

  • iOS8事先,供给将拉开授权的截图展现给用户,让用户依据截图去开启授权
  • iOS8后头,会自动弹出设置窗口,让用户采取是或不是须求开启授权
    • iOS初叶大家能够依照UXC60L直接跳转到相应的设置界面

OC:

//  当授权状态发生改变时调用
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{

    switch (status) {
        case kCLAuthorizationStatusNotDetermined:
            NSLog(@"用户未选择");
            break;
        // 暂时没用,应该是苹果预留接口
        case kCLAuthorizationStatusRestricted:
            NSLog(@"受限制");
            break;
        // 真正被拒绝、定位服务关闭等影响定位服务的行为都会进入被拒绝状态
        case kCLAuthorizationStatusDenied:

            if ([CLLocationManager locationServicesEnabled]) { // 定位服务开启
                NSLog(@"真正被用户拒绝");

                //  跳转到设置界面
                NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];

                if ([[UIApplication sharedApplication] canOpenURL:url]) {   // url地址可以打开
                    [[UIApplication sharedApplication] openURL:url];
                }
            } else {
                NSLog(@"服务未开启");
            }

            break;
        case kCLAuthorizationStatusAuthorizedAlways:
            NSLog(@"前后台定位授权");
            break;
        case kCLAuthorizationStatusAuthorizedWhenInUse:
            NSLog(@"前台定位授权");
            break;

        default:
            break;
    }
}

swift:

func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {

        switch status {
        case .NotDetermined:
            print("用户未选择")
        case .Restricted:
            print("受限制")
        case.Denied:
            print("被拒绝")
            if CLLocationManager .locationServicesEnabled() { // 定位服务开启
                print("用户真正拒绝")

                // 跳转到设置界面
                if #available(iOS 8.0, *) {
                    let url = NSURL(string: UIApplicationOpenSettingsURLString)
                    if UIApplication.sharedApplication().canOpenURL(url!) {
                        UIApplication.sharedApplication().openURL(url!)
                    }
                }
            } else {
                print("服务未开启")
            }
        case .AuthorizedAlways:
            print("前后台定位授权")
        case .AuthorizedWhenInUse:
            print("前台定位授权")
        }
    }

恒定服务未开启恐怕被用户真正拒绝意况下的地方处理

  • iOS8事先,要求将打开授权的截图显示给用户,让用户依照截图去开启授权
  • iOS8过后,会自动弹出设置窗口,让用户挑选是不是需求敞开授权
    • iOS初阶我们得以遵照U翼虎L直接跳转到相应的设置界面

OC:

//  当授权状态发生改变时调用
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{

    switch (status) {
        case kCLAuthorizationStatusNotDetermined:
            NSLog(@"用户未选择");
            break;
        // 暂时没用,应该是苹果预留接口
        case kCLAuthorizationStatusRestricted:
            NSLog(@"受限制");
            break;
        // 真正被拒绝、定位服务关闭等影响定位服务的行为都会进入被拒绝状态
        case kCLAuthorizationStatusDenied:

            if ([CLLocationManager locationServicesEnabled]) { // 定位服务开启
                NSLog(@"真正被用户拒绝");

                //  跳转到设置界面
                NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];

                if ([[UIApplication sharedApplication] canOpenURL:url]) {   // url地址可以打开
                    [[UIApplication sharedApplication] openURL:url];
                }
            } else {
                NSLog(@"服务未开启");
            }

            break;
        case kCLAuthorizationStatusAuthorizedAlways:
            NSLog(@"前后台定位授权");
            break;
        case kCLAuthorizationStatusAuthorizedWhenInUse:
            NSLog(@"前台定位授权");
            break;

        default:
            break;
    }
}

swift:

func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {

        switch status {
        case .NotDetermined:
            print("用户未选择")
        case .Restricted:
            print("受限制")
        case.Denied:
            print("被拒绝")
            if CLLocationManager .locationServicesEnabled() { // 定位服务开启
                print("用户真正拒绝")

                // 跳转到设置界面
                if #available(iOS 8.0, *) {
                    let url = NSURL(string: UIApplicationOpenSettingsURLString)
                    if UIApplication.sharedApplication().canOpenURL(url!) {
                        UIApplication.sharedApplication().openURL(url!)
                    }
                }
            } else {
                print("服务未开启")
            }
        case .AuthorizedAlways:
            print("前后台定位授权")
        case .AuthorizedWhenInUse:
            print("前台定位授权")
        }
    }

前言:
本章会利用OC和Swift分别展开落到实处,需求理解Swift的伙伴能够翻一下事先的博文

地理编码和反地理编码

  • 地理编码:指依照地质关键字,将其转换成对应的经纬度等消息
  • 反地理编码:指依照经纬度音信,将其转换来对应的省市区等音信
  • CLPlacemark(地球表面对象)
    • location:CLLocation类型,地方对象的新闻,包蕴经纬度,海拔等
    • region:CLRegion类型,地球表面对象对应区域
    • addressDictionary:NSDictionary类型,存放省市,街道等消息
    • name:NSString类型,地址全称
    • thoroughfare:NSString类型,街道名称
    • locality:NSString类型,城市称号
    • administrativeArea:NSString类型,省名称
    • country:NSString类型,国家名称
  • 注意
    • 务必联网
    • 偶然反地理编码时会找不到相应音讯,要求尝试更换经纬度

OC:

CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    // 地理编码
    [geocoder geocodeAddressString:@"福建省厦门市" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {

        CLPlacemark *placeM = [placemarks lastObject];

        NSLog(@"维度:%@ -- 经度:%@", @(placeM.location.coordinate.latitude).stringValue, @(placeM.location.coordinate.longitude).stringValue);
    }];

    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    // 反地理编码
    CLLocationDegrees latitude = 24.490474;
    CLLocationDegrees longitude = 118.11022;
    CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        NSLog(@"地址:%@", [placemarks firstObject].name);
    }];

swift:

let geocoder = CLGeocoder()
        // 地理编码
        geocoder.geocodeAddressString("福建省厦门市") { (placemarks, error) in

            let placeM = placemarks?.last

            print("维度\(placeM?.location?.coordinate.latitude) -- 经度\(placeM?.location?.coordinate.longitude)")
        }

        // 反地理编码
        let latitude : CLLocationDegrees = 24.490474
        let longitude : CLLocationDegrees = 118.11022
        let location = CLLocation(latitude: latitude, longitude: longitude)

        geocoder.reverseGeocodeLocation(location) { (placemarks, error) in
            print("地址:\(placemarks?.first?.name)")
        }

    }

先到那,方今太忙,过两天找个日子依照定位做个小品种再享受出去
小品种地址

iOS8随后定位

  • 从iOS8方始,苹果特别增强了对用户隐秘的掩护,当APP想范围用户隐衷音讯的时候,系统不再自动弹出对话框让用户授权,为了能让系统自动弹出用户授权界面,必要开始展览上边安装

    • 涸泽而渔方案:调用iOS8的API,主动请求用户授权
<!-- -->

    // 注意:根据官方文档的解释,在使用下面2个方法的时候,如果不在info.plist中配置NSLocationWhenInUseUsageDescription这个key,那么方法都不会生效
    // 请求前台定位授权
        - (void)requestWhenInUseAuthorization

    // 注意:根据官方文档的解释,在使用下面2个方法的时候,如果不在info.plist中配置`NSLocationAlwaysUsageDescription`这个key,那么方法都不会生效
    // 请求前后台定位授权
        - (void)requestAlwaysAuthorization

OC:

- (CLLocationManager *)manager
{
    if (_manager == nil) {
        _manager = [[CLLocationManager alloc] init];

        _manager.delegate = self;

        // 需要注意的是,必须在info.plist文件中配置’NSLocationWhenInUseUsageDescription‘这个key,否则下面方法无效(官方注释有提到)
        // 请求前台授权
        [_manager requestWhenInUseAuthorization];
        // 请求前后台授权
//        [_manager requestAlwaysAuthorization];
    }

    return _manager;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self.manager startUpdatingLocation];
}

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    NSLog(@"定位到了");

    [self.manager stopUpdatingLocation];
}

swift:

class ViewController: UIViewController {

    lazy var locationMgr : CLLocationManager = {

        let locationMgr = CLLocationManager()

        locationMgr.delegate = self

        // 记得设置相应的授权请求Key
        // 请求前台定位授权
        locationMgr.requestWhenInUseAuthorization()
        // 请求前后台定位授权
        locationMgr.requestAlwaysAuthorization()

        return locationMgr

    }()

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

        // 开启定位
        locationMgr.startUpdatingLocation()
    }


}

//MARK: - CLLocationManager代理
extension ViewController : CLLocationManagerDelegate {

    // 当定位到位置后调用
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        print("定位到了")

        manager.stopUpdatingLocation()
    }
}

startMonitoringSignificantLocationChanges(重庆大学任务变动监听)

  • 当地方发生较大转移后会调用这些服务(基于基站定位,所以须求求有电话模块)
    • 优势:当APP被完全关闭后,也基本上能用到岗位布告,并且让APP进入后台处理,耗能量小
    • 劣势:定位精度相对于专业定点服务较低,更新的频率遵照目前地方紧邻的基站密度决定

原则性适配

  • 诚如我们适配版本都会咬定当前设备的版本,然后再实行相应的适配操作,那边就介绍另一种对比简单的适配情势
    • 通过respondsToSelector:方法来判定方式是不是可响应,能够的话再履行

OC:

if ([_manager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {

      // 需要注意的是,必须在info.plist文件中配置’NSLocationWhenInUseUsageDescription‘这个key,否则下面方法无效(官方注释有提到)
      // 请求前台授权
      [_manager requestWhenInUseAuthorization];
}

if ([_manager respondsToSelector:@selector(requestAlwaysAuthorization)]) {

     // 请求前后台授权(无论是否开启后台模式都可以获取位置信息,并且不会出现蓝条提示)
      [_manager requestAlwaysAuthorization];
}

swift:

// 记得设置相应的授权请求Key
        // 根据当前系统版本适配
        // 当前版本是8.0及以上
        if #available(iOS 8.0, *) {
            // 请求前台定位授权
            locationMgr.requestWhenInUseAuthorization()
        }
        if #available(iOS 8.0, *) {
            // 请求前后台定位授权
            locationMgr.requestAlwaysAuthorization()
        }
  • iOS9恒定变化
    • 前台定位于iOS8无变化
      • 后台定位
        • 办法一:在前台定位授权基础上,勾选后台情势location
          updates之后,供给卓殊设置属性allowsBackgroundLocationUpdates
          = YES
        • 方法二:间接呼吁前后台定位授权,设置属性allowsBackgroundLocationUpdates
          = YES,开启后台形式

相关文章