IOS CoreLocation实现系统自带定位的方法
CoreLocation是iOSSDK中一个提供设备位置的框架。可以使用三种技术来获取位置:GPS、蜂窝或WiFi。在这些技术中,GPS最为精准,如果有GPS硬件,CoreLocation将优先使用它。如果设备没有GPS硬件(如WiFiiPad)或使用GPS获取当前位置时失败,CoreLocation将退而求其次,选择使用蜂窝或WiFi。
CoreLocation的大多数功能是由位置管理器(CLLocationManager)提供的,可以使用位置管理器来指定位置更新的频率和精度,以及开始和停止接收这些更新。
要使用位置管理器,必须首先将框架CoreLocation加入到项目中,再导入其接口文件:
#import<CoreLocation/CoreLocation.h>
并初始化位置管理器,指定更新代理,以及一些更新设置,然后更新
CLLocationManager*locManager=[[CLLocationManageralloc]init]; locManager.delegate=self; [locManagerstartUpdatingLocation];
位置管理器委托(CLLocationManagerDelegate)有两个与位置相关的方法:
-(void)locationManager:(CLLocationManager*)managerdidUpdateLocations:(NSArray*)locations { CLLocation*curLocation=[locationslastObject]; if(curLocation.horizontalAccuracy>0) { NSLog(@"当前位置:%.0f,%.0f+/-%.0fmeters",curLocation.coordinate.longitude, curLocation.coordinate.latitude, curLocation.horizontalAccuracy); } if(curLocation.verticalAccuracy>0) { NSLog(@"当前海拔高度:%.0f+/-%.0fmeters",curLocation.altitude,curLocation.verticalAccuracy); } }
-(void)locationManager:(CLLocationManager*)managerdidFailWithError:(NSError*)error {//此方法为定位失败的时候调用。并且由于会在失败以后重新定位,所以必须在末尾停止更新 if(error.code==kCLErrorLocationUnknown) { NSLog(@"Currentlyunabletoretrievelocation."); } elseif(error.code==kCLErrorNetwork) { NSLog(@"Networkusedtoretrievelocationisunavailable."); } elseif(error.code==kCLErrorDenied) { NSLog(@"Permissiontoretrievelocationisdenied."); [managerstopUpdatingLocation]; } }
第一个方法处理定位成功,manager参数表示位置管理器实例;locations为一个数组,是位置变化的集合,它按照时间变化的顺序存放。如果想获得设备的当前位置,只需要访问数组的最后一个元素即可。集合中每个对象类型是CLLocation,它包含以下属性:
coordinate—坐标。一个封装了经度和纬度的结构体。
altitude—海拔高度。正数表示在海平面之上,而负数表示在海平面之下。
horizontalAccuracy—位置的精度(半径)。位置精度通过一个圆表示,实际位置可能位于这个圆内的任何地方。这个圆是由coordinate(坐标)和horizontalAccuracy(半径)共同决定的,horizontalAccuracy的值越大,那么定义的圆就越大,因此位置精度就越低。如果horizontalAccuracy的值为负,则表明coordinate的值无效。
verticalAccuracy—海拔高度的精度。为正值表示海拔高度的误差为对应的米数;为负表示altitude(海拔高度)的值无效。
speed—速度。该属性是通过比较当前位置和前一个位置,并比较它们之间的时间差异和距离计算得到的。鉴于CoreLocation更新的频率,speed属性的值不是非常精确,除非移动速度变化很小。
应用程序开始跟踪用户的位置时,将在屏幕上显示一个是否允许定位的提示框。如果用户禁用定位服务,iOS不会禁止应用程序运行,但位置管理器将生成错误。
第二个方法处理这种定位失败,该方法的参数指出了失败的原因。如果用户禁止应用程序定位,error参数将为kCLErrorDenied;如果CoreLocation经过努力后无法确认位置,error参数将为kCLErrorLocationUnknown;如果没有可供获取位置的源,error参数将为kCLErrorNetwork。
通常,CoreLocation将在发生错误后继续尝试确定位置,但如果是用户禁止定位,它就不会这样做;在这种情况下,应使用方法stopUpdatingLocation停止位置管理器。
可根据实际情况来指定位置精度。例如,对于只需确定用户在哪个国家的应用程序,没有必要要求CoreLocation的精度为10米。要指定精度,可在启动位置更新前设置位置管理器的desiredAccuracy。有6个表示不同精度的枚举值:
externconstCLLocationAccuracykCLLocationAccuracyBestForNavigation; externconstCLLocationAccuracykCLLocationAccuracyBest; externconstCLLocationAccuracykCLLocationAccuracyNearestTenMeters; externconstCLLocationAccuracykCLLocationAccuracyHundredMeters; externconstCLLocationAccuracykCLLocationAccuracyKilometer; externconstCLLocationAccuracykCLLocationAccuracyThreeKilometers;
对位置管理器启动更新后,更新将不断传递给位置管理器委托,直到停止更新。您无法直接控制这些更新的频率,但可使用位置管理器的属性distanceFilter进行间接控制。在启动更新前设置属性distanceFilter,它指定设备(水平或垂直)移动多少米后才将另一个更新发送给委托。下面的代码使用适合跟踪长途跋涉者的设置启动位置管理器:
CLLocationManager*locManager=[[CLLocationManageralloc]init]; locManager.delegate=self; locManager.desiredAccuracy=kCLLocationAccuracyHundredMeters;//定位精度百米以内 locManager.distanceFilter=200;//水平或者垂直移动200米调用代理更新位置 [locManagerstartUpdatingLocation];//启动位置更新
P.s.定位要求的精度越高、属性distanceFilter的值越小,应用程序的耗电量就越大。
位置管理器有一个headingAvailable属性,它指出设备是否装备了磁性指南针。如果该属性为YES,就可以使用CoreLocation来获取航向(heading)信息。接收航向更新与接收位置更新极其相似,要开始接收航向更新,可指定位置管理器委托,设置属性headingFilter以指定要以什么样的频率(以航向变化的度数度量)接收更新,并对位置管理器调用方法startUpdatingHeading:
位置管理器委托协议定义了用于接收航向更新的方法。该协议有两个与航向相关的方法:
-(BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager*)manager { returnYES; } -(void)locationManager:(CLLocationManager*)managerdidUpdateHeading:(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*)managerdidUpdateHeading:(CLHeading*)newHeading { if(newHeading.headingAccuracy>=0) { NSString*headingDesc=[NSStringstringWithFormat:@"%.0fdegrees(true),%.0fdegrees(magnetic)",newHeading.trueHeading,newHeading.magneticHeading]; NSLog(@"%@",headingDesc); } }
trueHeading和magneticHeading分别表示真实航向和磁性航向。如果位置服务被关闭了,GPS和wifi就只能获取magneticHeading(磁场航向)。只有打开位置服务,才能获取trueHeading(真实航向)。
下面的代码演示了,当存在一个确定了经纬度的地点,当前位置离这个地点的距离及正确航向:
#import"ViewController.h" #definekDestLongitude113.12//精度 #definekDestLatitude22.23//纬度 #definekRad2Deg57.2957795//180/π #definekDeg2Rad0.0174532925//π/180 @interfaceViewController() @property(strong,nonatomic)IBOutletUILabel*lblMessage; @property(strong,nonatomic)IBOutletUIImageView*imgView; @property(strong,nonatomic)CLLocationManager*locationManager; @property(strong,nonatomic)CLLocation*recentLocation; -(double)headingToLocation:(CLLocationCoordinate2D)desiredcurrent:(CLLocationCoordinate2D)current; @end @implementationViewController -(void)viewDidLoad { [superviewDidLoad]; self.locationManager=[[CLLocationManageralloc]init]; self.locationManager.delegate=self; self.locationManager.desiredAccuracy=kCLLocationAccuracyThreeKilometers; self.locationManager.distanceFilter=1609;//1英里≈1609米 [self.locationManagerstartUpdatingLocation]; if([CLLocationManagerheadingAvailable]) { self.locationManager.headingFilter=10;//10° [self.locationManagerstartUpdatingHeading]; } } /* *AccordingtoMovableTypeScripts *http://mathforum.org/library/drmath/view/55417.html * *Javascript: * *vary=Math.sin(dLon)*Math.cos(lat2); *varx=Math.cos(lat1)*Math.sin(lat2)- *Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon); *varbrng=Math.atan2(y,x).toDeg(); */ -(double)headingToLocation:(CLLocationCoordinate2D)desiredcurrent:(CLLocationCoordinate2D)current { doublelat1=current.latitude*kDeg2Rad; doublelat2=desired.latitude*kDeg2Rad; doublelon1=current.longitude; doublelon2=desired.longitude; doubledlon=(lon2-lon1)*kDeg2Rad; doubley=sin(dlon)*cos(lat2); doublex=cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(dlon); doubleheading=atan2(y,x); heading=heading*kRad2Deg; heading=heading+360.0; heading=fmod(heading,360.0); returnheading; } //处理航向 -(void)locationManager:(CLLocationManager*)managerdidUpdateHeading:(CLHeading*)newHeading { if(self.recentLocation!=nil&&newHeading.headingAccuracy>=0) { CLLocation*destLocation=[[CLLocationalloc]initWithLatitude:kDestLatitudelongitude:kDestLongitude]; doublecourse=[selfheadingToLocation:destLocation.coordinatecurrent:self.recentLocation.coordinate]; doubledelta=newHeading.trueHeading-course; if(abs(delta)<=10) { self.imgView.image=[UIImageimageNamed:@"up_arrow.png"]; } else { if(delta>180) { self.imgView.image=[UIImageimageNamed:@"right_arrow.png"]; } elseif(delta>0) { self.imgView.image=[UIImageimageNamed:@"left_arrow.png"]; } elseif(delta>-180) { self.imgView.image=[UIImageimageNamed:@"right_arrow.png"]; } else { self.imgView.image=[UIImageimageNamed:@"left_arrow.png"]; } } self.imgView.hidden=NO; } else { self.imgView.hidden=YES; } } //处理定位成功 -(void)locationManager:(CLLocationManager*)managerdidUpdateLocations:(NSArray*)locations { CLLocation*curLocation=[locationslastObject]; if(curLocation.horizontalAccuracy>=0) { self.recentLocation=curLocation; CLLocation*destLocation=[[CLLocationalloc]initWithLatitude:kDestLatitudelongitude:kDestLongitude]; CLLocationDistancedistance=[destLocationdistanceFromLocation:curLocation]; if(distance<500) { [self.locationManagerstopUpdatingLocation]; [self.locationManagerstopUpdatingHeading]; self.lblMessage.text=@"您已经到达目的地!"; } else { self.lblMessage.text=[NSStringstringWithFormat:@"距离目的地还有%f米",distance]; } } } //处理定位失败 -(void)locationManager:(CLLocationManager*)managerdidFailWithError:(NSError*)error { if(error.code==kCLErrorLocationUnknown) { NSLog(@"Currentlyunabletoretrievelocation."); } elseif(error.code==kCLErrorNetwork) { NSLog(@"Networkusedtoretrievelocationisunavailable."); } elseif(error.code==kCLErrorDenied) { NSLog(@"Permissiontoretrievelocationisdenied."); [self.locationManagerstopUpdatingLocation]; self.locationManager=nil; } } -(void)didReceiveMemoryWarning { [superdidReceiveMemoryWarning]; //Disposeofanyresourcesthatcanberecreated. } @end
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。