Created
June 7, 2012 07:19
-
-
Save xxd/2887144 to your computer and use it in GitHub Desktop.
CoreLocation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //1.位置定位(最简单就是当前应用所有者所持设备的地理位置),主要用到的API类 CLLicationManager。 | |
| //iOS提供了一个叫作CoreLocation.framework的框架。使用他可以取到自己的定位信息(经纬度)。请参考下面代码片段 | |
| self.locationManager = [[CLLocationManager alloc]init]; | |
| if([CLLocationManager locationServicesEnabled]){ | |
| //设置代理 | |
| [self.locationManager setDelegate:self]; | |
| //设置精准度, | |
| [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; | |
| [self.locationManager startUpdatingLocation]; | |
| } | |
| //初始化了位置管理器,判断设备的定位功能是否开启开启的话设置代理,精度等参数后,开始服务。实现代理类方法,获取返回参数: | |
| #pragma mark- | |
| #pragma locationManagerDelegate methods | |
| - (void)locationManager:(CLLocationManager *)manager | |
| didUpdateToLocation:(CLLocation *)newLocation | |
| fromLocation:(CLLocation *)oldLocation | |
| { | |
| self.coordinate = [newLocation coordinate]; | |
| self.altitude = [newLocation altitude]; | |
| NSString *lat = [[NSString alloc] initWithFormat:@"%f",self.coordinate.latitude]; | |
| NSString *lon = [[NSString alloc] initWithFormat:@"%f",self.coordinate.longitude]; | |
| NSString *alt = [[NSString alloc] initWithFormat:@"%f",self.altitude]; | |
| //更新定位信息方法 | |
| NSLog(@"delegate %f,%f",self.coordinate.latitude,self.coordinate.longitude); | |
| self.latitudeText.text = lat; | |
| self.longitudeText.text = lon; | |
| self.altitudeText.text = alt; | |
| } | |
| - (void)locationManager:(CLLocationManager *)manager | |
| didFailWithError:(NSError *)error | |
| { | |
| //定位失败 | |
| } | |
| //如上面代码所示CLLocationManager就是用于获取定位信息对象类,在实际应用中可以根据自己的需要来设置定位的更新频率以及定位准确度。 | |
| // *其中代码中的distanceFilter表示更新位置的距离,假如超过设定值则进行定位更新,否则不更新。 | |
| // *代码中的kCLDistanceFilterNone表示不设置距离过滤,即随时更新地理位置。desiredAccuracy属性表示取得定位的精度,kCLLocationAccuracyBest表示最精确,但也预示着需要消耗更多的时间和电量,所以应该根据需要设定。 | |
| // *那么CLLocationManager是通过什么方法来开启定位的呢?他是通过调用startUpdatingLocation开启定位功能,然后使用stopUpdatingLocation停止定位,其中定位信息是通过loctionManager:didUpdateToLocation:fromLocation;委托方法来通知委托对象的,因此委托对象必须实现CLLocationManagerDelegate委托。 | |
| // *在返回定位信息委托方法中主要的两个参数是newLocation和oldLocation,newLocation表示最新定位,oldLocation表示上一次的定位信息。这两个都是CLLocation对象。以下是CLLocation的属性说明: | |
| //altitude 海拔高度 | |
| //coordinate 经纬度 | |
| //course 行驶方向 | |
| //horizontalAccuracy 水平方向的精确度 | |
| //Speed 行驶速度 | |
| //timestamp 时间戳 | |
| //verticalAccuracy 垂直方向的精确度 | |
| // 2 显示地图,MapKit。比如我们定位了一个经度 30.002,纬度为199.232.最简单的,我们直接在提供的视图上定位到这个点。但是我们知道,更多的时候,我们希望显示这个点的更多数据信息(比如街道,XXX路),更甚至是周边的。这个就需要庞大的数据包支持了,因为我没做过这方面的,只是简单知道可以通过google公开的一个web端接口获取数据。当你取到了一个经纬度信息时,也许还有这样的一个需求,那就是当前的经纬度所对应的地理位置信息是什么。那么这时候我们需要用到框架来为我们实现这一功能,那就是MapKit.framework。在这个框架中有一个叫MKReverseGeocoder的类可以帮助我们实现反向解析地理位置。请看一下代码: | |
| - (void)locationManager:(CLLocationManager *)manager | |
| didUpdateToLocation:(CLLocation *)newLocation | |
| fromLocation:(CLLocation *)oldLocation { | |
| MKReverseGeocoder *geocoder = [[MKReverseGeocoder alloc]initWithCoordinate:newLocation.coordinate]; | |
| geocoder.delegate= self; | |
| [geocoderstart]; | |
| } | |
| - (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark { | |
| NSLog(@"\n country:%@\n postalCode:%@\n ISOcountryCode:%@\nlocality:%@\n subLocality:%@\n administrativeArea:%@\nsubAdministrativeArea:%@\n thoroughfare:%@\n subThoroughfare:%@\n", | |
| placemark.country, | |
| placemark.postalCode, | |
| placemark.ISOcountryCode, | |
| placemark.administrativeArea, | |
| placemark.subAdministrativeArea, | |
| placemark.locality, | |
| placemark.subLocality, | |
| placemark.thoroughfare, | |
| placemark.subThoroughfare); | |
| } | |
| - (void)reverseGeocoder:(MKReverseGeocoder*)geocoder didFailWithError:(NSError*)error { | |
| NSLog(@"reverse geocoder fail!!"); | |
| } | |
| //上面的代码是在获取到经纬度后,立刻进行反向地理位置解析的。其实MKReverseGeocoder用法也比较简单,通过经纬度初始化后直接调用start方法就可以实现反向解析了,然后等待返回,其返回是通过委托形式通知的。所以委托对象必须实现MKReverseGeocoderDelegate委托。解析成功后会返回一个MKPlacemark的对象里面包含了相关的地理位置信息(包括国家、地区、街道等)。但从iOS5之后MKReverseGeocoder成为了不推荐使用的类。因此有一个新的类取代了他的作用,那就是CLGeocoder类,使用该类进行反向解析也非常容易,请看下面代码: | |
| CLGeocoder *geocoder=[[CLGeocoder alloc] init]; | |
| [geocoder reverseGeocodeLocation:newLocation | |
| completionHandler:^(NSArray *placemarks,NSError*error){ | |
| CLPlacemark*placemark=[placemarks objectAtIndex:0]; | |
| NSLog(@"name:%@\ncountry:%@\n postalCode:%@\n ISOcountryCode:%@\n ocean:%@\n inlandWater:%@\nlocality:%@\n subLocality:%@\n administrativeArea:%@\nsubAdministrativeArea:%@\n thoroughfare:%@\n subThoroughfare:%@\n", | |
| placemark.name, | |
| placemark.country, | |
| placemark.postalCode, | |
| placemark.ISOcountryCode, | |
| placemark.ocean, | |
| placemark.inlandWater, | |
| placemark.administrativeArea, | |
| placemark.subAdministrativeArea, | |
| placemark.locality, | |
| placemark.subLocality, | |
| placemark.thoroughfare, | |
| placemark.subThoroughfare); | |
| }]; | |
| // 从代码来看,CLGeocoder类没有使用委托的形式通知返回状态,而是通过block的方式进行回调,而且MKReverseGeocoder委托只返回了一个地标位置,但是CLGeocoder则返回了一个包含多个地标位置的数组,但这个数组在通常状态下是只有一个元素,如果存在多个元素那证明了给定解析的经纬度被解析到多个不同的地标信息。如果解析错误或者调用cancel方法则此参数为nil。 | |
| //解析google map服务 | |
| latNum = [[NSNumber alloc] initWithFloat:lat]; | |
| lonNum = [[NSNumber alloc] initWithFloat:lon]; | |
| NSURL * aurl = [NSURL URLWithString:[NSString stringWithFormat: | |
| @"http://ditu.google.com/maps/geo?q=%@,%@&output=json&oe=utf8&hl=zh-CN&sensor=false",latNum,lonNum]]; | |
| NSURLRequest *request = [[NSURLRequest alloc] initWithURL:aurl]; | |
| self.connection1=[NSURLConnection connectionWithRequest:request delegate:self]; | |
| - (void)connectionDidFinishLoading:(NSURLConnection *)connection | |
| { | |
| NSString *jsonString = [[NSString alloc] initWithData:self.amutabledata encoding:NSUTF8StringEncoding]; | |
| NSDictionary * jsonDic = [jsonString JSONValue]; | |
| NSArray * jsonarr = [jsonDic objectForKey:@"Placemark"]; | |
| NSDictionary *dic2 = [jsonarr objectAtIndex:0]; | |
| NSString *name1 = [dic2 objectForKey:@"address"]; | |
| } | |
| // 3、放置大头针 MKAnnotation | |
| // 想更加形象地表现出位置信息靠文字的描述是远远不够的,因为使用地图来显示地理位置将会给用户带来全新的体验。在iOS里面已经将Google地图封装到SDK里面了,我们可以用很少的代码来实现很多在地图上的操作(如标记位置、绘画线路等)。下面的代码是生成一张地图并显示到界面上: | |
| - (void)viewDidLoad{ | |
| [super viewDidLoad]; | |
| MKMapView *mapView=[[MKMapView alloc] initWithFrame:CGRectMake(0.0,0.0, 320.0, 460.0)]; | |
| mapView.delegate = self; | |
| [self.view addSubview:mapView]; | |
| [mapViewrelease]; | |
| } | |
| // 这够简单吧,上面的设置地图委托对象是因为在下面要标记地理位置时需要用到的。那么如何把取到的经纬度信息显示到地图上呢?其实每个坐标信息在地图中显示后都对应一个MKAnnotationView,而MKAnnotationView又负责解析了一个实现MKAnnotation协议的数据对象。因此我们首先要做的事情就是把取到的经纬度转换为MKAnnotation协议对象。先定义一个实现MKAnnotation协议的类: | |
| @interface DemoAnnotation : NSObject<MKAnnotation> { | |
| CLLocationCoordinate2D _coordinate; | |
| } | |
| -(id)initWithCoordinate:(CLLocationCoordinate2D)coordinate; | |
| @end | |
| @implementation DemoAnnotation | |
| @synthesize coordinate=_coordinate; | |
| -(id)initWithCoordinate:(CLLocationCoordinate2D)coordinate{ | |
| if(self = [superinit]) { | |
| _coordinate=coordinate; | |
| } | |
| returnself; | |
| } | |
| -(void)setCoordinate:(CLLocationCoordinate2D)newCoordinate{ | |
| _coordinate=newCoordinate; | |
| } | |
| -(NSString*)title{ | |
| return @"我的位置"; | |
| } | |
| -(NSString*)subtitle{ | |
| return nil; | |
| } | |
| @end | |
| // 上面的类只是简单地保存了经纬度信息。记得注意的是MKAnnotation协议中的title和subtitle的作用,如果你在显示AnnotationView设置其canShowCallout属性为YES时,则当用户点击AnnotationView时会弹出一个Callout视图,用于显示title和subtitle,假如设置title为nil那么即使canShowCallout为YES也不会弹出Callout视图。接下来要改写一下获取定位成功后的方法,等待获取定位成功后把经纬度设置到地图上显示。实现代码如下: | |
| - (void)locationManager:(CLLocationManager *)manager | |
| didUpdateToLocation:(CLLocation *)newLocation | |
| fromLocation:(CLLocation *)oldLocation | |
| { | |
| DemoAnnotation *annotation = [[DemoAnnotation alloc] initWithCoordinate:newLocation.coordinate]; | |
| [_mapView addAnnotation:annotation]; | |
| [annotation release]; | |
| MKReverseGeocoder *geocoder = [[MKReverseGeocoder alloc]initWithCoordinate:newLocation.coordinate]; | |
| geocoder.delegate= self; | |
| [geocoderstart]; | |
| } | |
| // 上述代码中加粗部分的代码就是把经纬度信息封装到刚才定义好的对象中。然后通过addAnnotation方法传递给MapView;这里的_mapView是把之前viewDidLoad方法中的临时变量改变为类属性以达到跨方法引用的目的。经过上面步骤已经把我的位置引入到地图里面了,但现在还不会显示在地图上,因为还需要实现MapView中的协议,告诉MapView如何显示你Annotation。以下代码采用iOS中默认的大头针样式来显示位置。如下: | |
| - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation | |
| { | |
| NSString*annotationViewId=@"CurrentUserAnnotationView"; | |
| MKPinAnnotationView *annotationView= (MKPinAnnotationView *)[mapViewdequeueReusableAnnotationViewWithIdentifier:annotationViewId]; | |
| if(annotationView==nil) | |
| { | |
| annotationView = [[[MKPinAnnotationViewalloc] initWithAnnotation:annotation reuseIdentifier:annotationViewId]autorelease]; | |
| annotationView.canShowCallout = YES; | |
| } | |
| return annotationView; | |
| } | |
| // 上面的协议方法就是MapView告诉你他需要显示哪个annotation,然后显示的样式由用户你自己决定,但必须要继承MKAnnotationView类。到这里对于定位和地图的应用就告一段落了,当然关于MKMapView还有一些更加高级的特性,例如:动态编辑Annotation、绘画路线图等应用我在这里暂时不说了,等偶再研究透彻一点再给大家分享。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment