zoukankan      html  css  js  c++  java
  • 定位 问题

    注意

    if(IOS8){

                // 使用期间

                [_locationManager requestWhenInUseAuthorization];

            }

     // 精确度

            _locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;

            // 位移多少后 重新定位

            _locationManager.distanceFilter = kCLDistanceFilterNone;

    经纬度 
    位置信息是通过使用CLLocation类的实例从Location Manager那里得到的。这个类有5各属性。latitude和longitude被封装在coordinate属性中。 
    获取方式如下: 
    CLLocationDegrees latitude = theLocation.coordinate.latitude; 
    CLLocationDegrees longitude = theLocation.coordinate.longitude; 
    CLLocation对象还可以告诉你精确度。 
    horizontalAccuracy属性描述调整的中心点。horizontalAccuracy值越大越不精确。 
    CLLocation 还有一个叫altitude的属性用来表示海拔 
    CLLocationDistance altitude = theLocation.altitude; 
    每一个CLLocation对象都有一个叫verticalAccuracy的属性来判断精确度。海拔数值可能会有verticalAccuracy大小的误差,当verticalAccuracy为负值时,那是Core Location在通知你不能获取海拔高度。 
    CLLocation的另一个属性timestamp用来告诉Location Manager是什么时候定位的。CLLocation还有一个实例方法来告诉你的两个CLLocation对象之间的距离。这个方法叫:getDistanceFrom: 
    它是这样工作的: 
    CLLocationDistance distance = [fromLocation getDistanceFrom:toLocation]; 
    返回两个时间段内的距离,有时候它是不考虑海拔的,所以要自己计算距离。 

    //方向的更新
    - (void)locationManager:(CLLocationManager *)manager
           didUpdateHeading:(CLHeading *)newHeading;

    //用于判断是否显示方向的校对,返回yes的时候,将会校对正确之后才会停止,或者dismissheadingcalibrationdisplay方法解除。
    - (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager;  


    - (void)locationManager:(CLLocationManager *)manager
        didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region;

    - (void)locationManager:(CLLocationManager *)manager
            didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region;

    - (void)locationManager:(CLLocationManager *)manager
        rangingBeaconsDidFailForRegion:(CLBeaconRegion *)region
        withError:(NSError *)error ;

    //进入指定区域
    - (void)locationManager:(CLLocationManager *)manager
        didEnterRegion:(CLRegion *)region ;

    //离开指定的区域
    - (void)locationManager:(CLLocationManager *)manager
        didExitRegion:(CLRegion *)region;

    //定位失败
    - (void)locationManager:(CLLocationManager *)manager
        didFailWithError:(NSError *)error;

    //区域定位失败
    - (void)locationManager:(CLLocationManager *)manager
        monitoringDidFailForRegion:(CLRegion *)region
        withError:(NSError *)error ;

    //改变里授权的状态
    - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status ;

    //开始控制指定的区域
    - (void)locationManager:(CLLocationManager *)manager
        didStartMonitoringForRegion:(CLRegion *)region;

    //已经停止位置的更更新
    - (void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager ;

    //位置定位重新开始定位位置的更新
    - (void)locationManagerDidResumeLocationUpdates:(CLLocationManager *)manager ;

    //已经完成了推迟的更新
    - (void)locationManager:(CLLocationManager *)manager
        didFinishDeferredUpdatesWithError:(NSError *)error;

    //就是已经访问过的位置,就会调用这个表示已经访问过,这个在栅栏或者定位区域都是使用到的
    - (void)locationManager:(CLLocationManager *)manager didVisit:(CLVisit *)visit;

     

     

     

    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>

    接下来,需要分配并初始化一个位置管理器实例、指定将接收位置更新的委托并启动更新:

    CLLocationManager *locManager = [[CLLocationManager alloc] init];
    locManager.delegate = self;
    [locManager startUpdatingLocation];
    //[locManager stopUpdatingLocation];

    位置管理器委托(CLLocationManagerDelegate)有两个与位置相关的方法:

    复制代码
    - (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];
        }
    }
    复制代码

    可根据实际情况来指定位置精度。例如,对于只需确定用户在哪个国家的应用程序,没有必要要求Core Location的精度为10米。要指定精度,可在启动位置更新前设置位置管理器的desiredAccuracy。有6个表示不同精度的枚举值:

    复制代码
    extern const CLLocationAccuracy kCLLocationAccuracyBestForNavigation;
    extern const CLLocationAccuracy kCLLocationAccuracyBest;
    extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;
    extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;
    extern const CLLocationAccuracy kCLLocationAccuracyKilometer;
    extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;
    复制代码

    对位置管理器启动更新后,更新将不断传递给位置管理器委托,直到停止更新。您无法直接控制这些更新的频率,但可使用位置管理器的属性distanceFilter进行间接控制。在启动更新前设置属性distanceFilter,它指定设备(水平或垂直)移动多少米后才将另一个更新发送给委托。下面的代码使用适合跟踪长途跋涉者的设置启动位置管理器:

    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
  • 相关阅读:
    Mininet 搭建自定义网络
    struts 2 三目运算
    shell 变量自增(转)
    Java DES 加密和解密源码(转)
    java调用shell脚本
    shell 学习
    debian安装jdk6
    linux(debian) 安装jdk
    利用SecureCRT上传、下载文件(使用sz与rz命令)
    oracle之报错:ORA-00054: 资源正忙,要求指定 NOWAIT
  • 原文地址:https://www.cnblogs.com/yecong/p/6143705.html
Copyright © 2011-2022 走看看