Cowboy Tech

CoreLocation框架详解

定位基础及权限详解

Core Location框架为定位用户当前位置和方向(Heading)提供支持。负责从设备硬件收集信息并以异步方式报告给应用程序。

  1. 定位方式:Wifi、蜂窝式移动电话基站、GPS卫星
  2. 定位优先级:GPS、Wifi、蜂窝式移动电话基站
  3. 定位准确性:GPS卫星(准确性高,但局限性大,比较耗费设备电量)、Wifi及蜂窝式移动电话基站(Wifi依赖网络,蜂窝取决于基站密度,耗费流量)
  4. iOS开发中,不能指定使用哪种方式进行定位,iOS系统会根据设备情况和周围环境,采用一套最佳的定位解决方案。
  5. iOS设备通过定位来确定用户位置信息,因为涉及用户隐私问题,所以在用户使用地图定位功能之前会与用户之间有交互行为。
  6. 服务过程:用户进行定位授权,同意则进行定位操作,反之提示用户无授权无法进行定位操作。

通过CoreLocation实现定位功能

定位权限申请

在info.plist文件里设置以下属性,对应的string值将会显示在弹出的对话框

NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription

定位权限

if([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]){
    [_locationManager requestWhenInUseAuthorization];
    [_locationManager requestAlwaysAuthorization];
}

位置管理器CLLocationManager

ViewController

@interface ViewController () <CLLocationManagerDelegate,MKMapViewDelegate>

@property (nonatomic, strong) MKMapView * mapView;
@property (nonatomic, strong) CLLocationManager * locationManager;

@end

@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
[_mapView setDelegate:self];

//允许显示用户位置
[_mapView setShowsUserLocation:YES];
[_mapView setMapType:MKMapTypeStandard];
[self.view addSubview:_mapView];

//检测定位功能是否开启
if([CLLocationManager locationServicesEnabled]){        
    if(!_locationManager){       
        _locationManager = [[CLLocationManager alloc] init];

        //定位权限
        if([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]){
            [_locationManager requestWhenInUseAuthorization];
            [_locationManager requestAlwaysAuthorization];
        }

        //设置代理
        [_locationManager setDelegate:self];
        //设置定位精度
        [_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
        //设置距离筛选
        [_locationManager setDistanceFilter:100];
        //开始定位
        [_locationManager startUpdatingLocation];
        //设置开始识别方向
        //[_locationManager startUpdatingHeading];
    }       
}else{

    UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:nil
                                                         message:@"您没有开启定位功能"
                                                        delegate:nil
                                               cancelButtonTitle:@"确定"
                                               otherButtonTitles:nil, nil];
    [alertView show];
}

}

CLLocationManagerDelegate

授权状态发生改变的时候执行

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {

switch(status){

    case kCLAuthorizationStatusDenied:
    {
        UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:nil
                                                             message:@"定位功能没有开启" delegate:nil
                                                   cancelButtonTitle:@"确定" otherButtonTitles:nil,nil];
        [alertView show];
    }
        break;
    default:
        break;
}
}

定位成功以后调用

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

//[_locationManager stopUpdatingLocation];
CLLocation * location = locations.lastObject;

MKCoordinateRegion coordinateRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude), MKCoordinateSpanMake(0.1, 0.1));

[_mapView setRegion:[_mapView regionThatFits:coordinateRegion] animated:YES];

//[self reverseGeocoder:location];
}

定位失败

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(@"error:%@",error);
}

CLGeocoder

地理编码 - 地址转经纬度

CLGeocoder * geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:str completionHandler:^(NSArray *placemarks, NSError *error) {

    if(error || placemarks.count == 0){
        NSLog(@"error");
    }else{

        CLPlacemark * placemark = placemarks.firstObject;

        //设置显示区域
        MKCoordinateRegion coordinateRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(placemark.location.coordinate.latitude, placemark.location.coordinate.longitude), MKCoordinateSpanMake(0.1, 0.1));
        [_mapView setRegion:[_mapView regionThatFits:coordinateRegion] animated:YES];

        //设置标注
        MKPointAnnotation * pointAnnotation = [[MKPointAnnotation alloc] init];
        [pointAnnotation setTitle:placemark.name];
        [pointAnnotation setCoordinate:CLLocationCoordinate2DMake(placemark.location.coordinate.latitude, placemark.location.coordinate.longitude)];
        [_mapView addAnnotation:pointAnnotation];
    }  
}];

反地理编码 - 经纬度转地址

CLGeocoder * geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {

    if(error || placemarks.count == 0){
        NSLog(@"error");
    }else{

        CLPlacemark * placemark = placemarks.firstObject;

         //设置标注
        MKPointAnnotation * pointAnnotation = [[MKPointAnnotation alloc] init];
        [pointAnnotation setTitle:placemark.name];
        [pointAnnotation setCoordinate:CLLocationCoordinate2DMake(placemark.location.coordinate.latitude, placemark.location.coordinate.longitude)];
        [_mapView addAnnotation:pointAnnotation];

        //设置显示区域
        MKCoordinateRegion coordinateRegion = MKCoordinateRegionMake(CLLocationCoordinate2DMake(placemark.location.coordinate.latitude, placemark.location.coordinate.longitude), MKCoordinateSpanMake(0.1, 0.1));   
        [_mapView setRegion:[_mapView regionThatFits:coordinateRegion] animated:YES];

        NSLog(@"placemark:%@",[[placemark addressDictionary] objectForKey:@"City"]);
    }

}];

CLPlacemark存储地址信息

NSLog(@"placemark:%@",[[placemark addressDictionary] objectForKey:@"City"]);

屏幕触摸实现地理位置选择

长按设置坐标点

UILongPressGestureRecognizer * longpressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressed:)];
[_mapView addGestureRecognizer:longpressGestureRecognizer];


- (void)longPressed:(UILongPressGestureRecognizer *)recognizer {

if(recognizer.state == UIGestureRecognizerStateBegan){


    CGPoint point = [recognizer locationInView:_mapView];
    CLLocationCoordinate2D coordinate2D = [_mapView convertPoint:point toCoordinateFromView:_mapView];

    [_mapView removeAnnotations:_mapView.annotations];

    CLLocation * location = [[CLLocation alloc] initWithLatitude:coordinate2D.latitude longitude:coordinate2D.longitude];

    [self reverseGeocoder:location];

}
}

获取地图界面点

CGPoint point = [recognizer locationInView:_mapView];
CLLocationCoordinate2D coordinate2D = [_mapView convertPoint:point toCoordinateFromView:_mapView];

移除原有的标注

[_mapView removeAnnotations:_mapView.annotations];

自定义标注

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{
static NSString * key = @"key";
MKPinAnnotationView * pinAnnotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:key];

if(pinAnnotationView == nil){
    pinAnnotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:key];
    [pinAnnotationView setCanShowCallout:YES];
}

if([annotation isKindOfClass:[MKUserLocation class]]){
    [pinAnnotationView setPinColor:MKPinAnnotationColorRed];
    [((MKUserLocation *)annotation) setTitle:_titleString];
}else{
    [pinAnnotationView setPinColor:MKPinAnnotationColorPurple];
}
return pinAnnotationView;
}

默认的是个蓝色闪烁点,如果自定义的话,就是插个大头针

[_mapView setShowsUserLocation:YES];

CoreLocation相关功能补充

CLHeading介绍

//设置开始识别方向
[_locationManager startUpdatingHeading];

位置更新

//定位成功以后就停止位置更新
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
......
[_locationManager stopUpdatingLocation];

}

其他

文本框键盘退出

[_textField resignFirstResponder];

文本框输入的判断

if([_textField.text length] == 0){

    return;
}