iOS系统定位

CoreLocationManager使用

  • 前言

iOS9.0系统 didUpdateLocations代理方法中, 速度, 航向获取不到, 以后版本没有问题

iOS10以上app需要定位服务,请先在infoplist中添加位置权限

  • Privacy - Location When In Use Usage Description 需要时访问位置
  • Privacy - Location Always Usage Description 一直访问位置

手动获取定位信息

    BOOL enable = [CLLocationManager locationServicesEnabled];
    if (enable) {
        //手机定位权限未开启(针对全部应用)
        NSLog(@"系统定位已开启");
    } else {
        NSLog(@"系统定位未开启");
        UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"提示" message:@"系统定位尚未打开,请到【设定-隐私】中手动打开" preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction * tipsAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:nil];
        [alertVC addAction:tipsAction];
        [self presentViewController:alertVC animated:YES completion:nil];
    }
    
    NSInteger state = [CLLocationManager authorizationStatus];
    switch (state) {
        case kCLAuthorizationStatusDenied:
        {
            NSLog(@"定位服务开启,被拒绝");
                UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"提示" message:@"app定位权限尚未打开, 不能获取附近信息" preferredStyle:UIAlertControllerStyleAlert];
                UIAlertAction * tipsAction = [UIAlertAction actionWithTitle:@"打开" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                    //跳转到app的位置权限设置界面
                    NSURL*url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
                    if([[UIApplication sharedApplication] canOpenURL:url]) {
                        [[UIApplication sharedApplication] openURL:url];
                    }
                }];
                [alertVC addAction:tipsAction];
                
                UIAlertAction * tipsAction1 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
                [alertVC addAction:tipsAction1];
                [self presentViewController:alertVC animated:YES completion:nil];
            break;
        }
        case kCLAuthorizationStatusNotDetermined:
            NSLog(@"用户还未决定授权");
            break;
        case kCLAuthorizationStatusRestricted:
            NSLog(@"授权定位服务, 未知原因");
            break;
        case kCLAuthorizationStatusAuthorizedAlways:{
            NSLog(@"一直获得授权");
            break;
        }
        case kCLAuthorizationStatusAuthorizedWhenInUse:{
            NSLog(@"使用时获得授权");
            break;
        }
        default:
            
            break;
    }

开启定位功能

CoreLocationManager使用

//引入框架, 声明遵守协议
#import <CoreLocation/CoreLocation.h>
@interface ViewController ()<CLLocationManagerDelegate>
    @property (nonatomic, strong)  CLLocationManager *locationManager;
@end
     
- (CLLocationManager *)locationManager
{
    if (_locationManager == nil) {
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
//        _lm.distanceFilter = 0.5; //每隔多远定位一次, 距离过滤
        /**
         kCLLocationAccuracyBestForNavigation // 最适合导航
         kCLLocationAccuracyBest; // 最好的
         kCLLocationAccuracyNearestTenMeters; // 10m
         kCLLocationAccuracyHundredMeters; // 100m
         kCLLocationAccuracyKilometer; // 1000m
         kCLLocationAccuracyThreeKilometers; // 3000m
         */
        //精确度越高, 耗电, 定位时间长
        _locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;//渴望的准确性
        
        
        /** -------iOS8.0+定位适配-------- */
       
            //在plist中增加NSLocationWhenInUseUsageDescription和NSLocationAlwaysAndWhenInUsageDescription,两个key
            // 获得在使用中定位的授权
            [_locationManager requestWhenInUseAuthorization];
            //获得前后台定位授权, 这个方法包含上一个方法
            [_locationManager requestAlwaysAuthorization];
           //以上方法二选一 根据项目需求而定
        }
        // 允许后台获取用户位置(iOS9.0)
        if (@available(iOS 9.0, *)) {
            // 如果想要支持后台定位, 下面这个行代码必须写, 前提一定要勾选后台模式 location updates
            _locationManager.allowsBackgroundLocationUpdates = YES;
        } else {
            // Fallback on earlier versions
        }
        
        //9.0之后才有的, 就是在一定时间内按照distanceFilter的枚举来一层一层来定位, 如果超时就走didFailWithError: 方法(注意: 这个方法必须得有, 没有报错)
        if (@available(iOS 9.0, *)) {
//            [_locationManager requestLocation];
        } else {
            // Fallback on earlier versions
        }
    }
    return _locationManager;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    //开始定位
    [self.locationManager startUpdatingLocation];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    //结束定位
    [self.locationManager stopUpdatingLocation];
}

CLLocationManagerDelegate代理方法

// 代理返回经纬度等信息
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    CLLocation *newLocation = [locations lastObject];
    NSLog(@"%@", newLocation);

    // 判空处理
    if (newLocation.horizontalAccuracy < 0) {
        UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"提示" message:@"定位错误,请检查手机网络以及定位" preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction * tipsAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleCancel handler:nil];
        [alertVC addAction:tipsAction];
        [self presentViewController:alertVC animated:YES completion:nil];
        return;
    }

    // 获取定位经纬度
    CLLocationCoordinate2D coor2D = newLocation.coordinate;
    NSLog(@"纬度为:%f, 经度为:%f", coor2D.latitude, coor2D.longitude);
    
    // 获取定位海拔高度
    CLLocationDistance altitude = newLocation.altitude;
    NSLog(@"高度为:%f", altitude);
    
    // 获取定位水平精确度, 垂直精确度
    CLLocationAccuracy horizontalAcc = newLocation.horizontalAccuracy;
    CLLocationAccuracy verticalAcc = newLocation.verticalAccuracy;
    NSLog(@"%f, %f", horizontalAcc, verticalAcc);

    // 航向
    CLLocationDirection course = newLocation.course;
    NSLog(@"高度为:%f", course);
    
    // 速度
    CLLocationSpeed speed = newLocation.speed;
    NSLog(@"速度为:%f", speed);
}

授权状态发生改变时调用

/**
 *  授权状态发生改变时调用
 *  @param manager 位置管理者
 *  @param status  状态
 */
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
            // 用户还未决定
        case kCLAuthorizationStatusNotDetermined:
        {
        NSLog(@"用户还未决定");
        break;
        }
            // 访问受限
        case kCLAuthorizationStatusRestricted:
        {
        NSLog(@"访问受限");
        break;
        }
            // 定位关闭时和对此APP授权为never时调用
        case kCLAuthorizationStatusDenied:
        {
        // 定位是否可用(是否支持定位或者定位是否开启)
        if([CLLocationManager locationServicesEnabled]) {
            NSLog(@"app定位开启,但被用户拒绝");
        } else {
            NSLog(@"手机硬件定位关闭");
        }
        //            NSLog(@"被拒");
        break;
        }
            // 获取前后台定位授权
        case kCLAuthorizationStatusAuthorizedAlways:
            //        case kCLAuthorizationStatusAuthorized: // 失效,不建议使用
        {
        NSLog(@"获取前台和后台双定位");
        break;
        }
            // 获得前台定位授权
        case kCLAuthorizationStatusAuthorizedWhenInUse:
        {
        NSLog(@"获得前台定位授权");
        break;
        }
        default:
            break;
    }
}

地理编码

  • 地理编码, 地名得到经纬度
//地名得到经纬度
- (IBAction)geocodeQuery:(id)sender {
   CLGeocoder *geocode = [[CLGeocoder alloc] init];
   [geocode geocodeAddressString:@"杭州" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
   
       CLPlacemark *placemark = [placemarks firstObject];
       //得到的城市名字
       self.textView.text = placemark.name;
       self.txtLng.text = @(placemark.location.coordinate.longitude).stringValue;// 经度
       self.txtlat.text = @(placemark.location.coordinate.latitude).stringValue;//纬度
   }];
}
  • 反地理编码, 经纬度得到地名
//经纬度得到地名
- (IBAction)reverseGeocode:(id)sender {
    CLGeocoder *geocode = [[CLGeocoder alloc] init];
    // 创建CLLocation对象
    CLLocation *location = [[CLLocation alloc] initWithLatitude:[self.txtlat.text doubleValue] longitude:[self.txtLng.text doubleValue]];
    // 根据CLLocation对象进行反地理编码
    [geocode reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * __nullable placemarks, NSError * __nullable error) {
        // 包含区,街道等信息的地标对象
        CLPlacemark *placemark = [placemarks firstObject];
        // 城市名称
        //        NSString *city = placemark.locality;
        // 街道名称
        //        NSString *street = placemark.thoroughfare;
        // 全称
        NSString *name = placemark.name;
        self.textView.text = [NSString stringWithFormat:@"%@", name];
    }];
}

插大头针

1>. 首先我们要创建一个大头针的数据模型, 继承NSObject遵守<MKAnnotation>协议
//  MyAnnotation.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface MyAnnotation : NSObject<MKAnnotation>
//地理坐标// 用readWrite修饰也行
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
*以上三条是从代理复制过来的
//街道信息
@property (nonatomic, strong) NSString *streetAddress;
//城市信息
@property (nonatomic, strong) NSString *city;
//州, 省市信息
@property (nonatomic, strong) NSString *state;

- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate;

@end
//  MyAnnotation.m
#import "MyAnnotation.h"

@implementation MyAnnotation
 - (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate
{
    self = [super init];
    if (self) {
        self.coordinate = coordinate;
    }
    return self;
}
@end
2>. 将大头针数据模型添加到mapView上

举例1: 手指点击屏幕时, 获取屏幕坐标对应在地图中的经纬度, 来插大头针, 然后在大头针的标注中显示位置信息

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //移除其他大头针
    [self.mapView removeAnnotations:self.mapView.annotations];
    //在touchBegan中获取手指点击屏幕坐标
    CGPoint point = [[touches anyObject] locationInView:self.mapView];
    //我们利用mapView的方法来, 利用屏幕坐标point得到mapView地图中的经纬度
    CLLocationCoordinate2D coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
    //来初始化一个地理编码类
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    //初始化一个本地信息, 反地理方法能用到
    CLLocation *location = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
    //反地理编码, 给我个坐标, 我告诉你城市, 街道
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        // 就是取数组最后一个, [placemarks lastObiect]一样
        for (CLPlacemark *placemark in placemarks) {
            MyAnnotation *annotation = [[MyAnnotation alloc] initWithCoordinate:coordinate];//终于创建了大头针了
            annotation.title = placemark.locality;
            annotation.subTitle = placemark.administrativeArea;
            annotation.zip = placemark.postalCode;
            //添加大头针(注: 下面解释3. 大头针的代理方法)
            [self.mapView addAnnotation:annotation];
        }
        if ([placemarks count] > 0) {
            //设置当前手机地图的可视范围, 跟跨度差不多, 但跨度是角度, 东西, 南北跨度, 这个直接写多少米   
            MKCoordinateRegion viewReign = MKCoordinateRegionMakeWithDistance(coordinate, 10000, 10000);
            [self.mapView setRegion:viewReign];
        }
    }];


//当添加[self.mapView addAnnotation: annotation]时系统会回调委托协议MKMapViewDelegate
 — (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation方法, 我们需要实现这个方法, 才能实现在地图上添加标注的操作

例子2. 我们查询一个城市名字, 然后插个大头针子在地图上

[geocoder geocodeAddressString:@"杭州站" completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
            for (CLPlacemark *placemark in placemarks) {
                MyAnnotation *annotation = [[MyAnnotation alloc] initWithCoordinate:placemark.location.coordinate];
                annotation.city = placemark.locality;
                annotation.state = placemark.administrativeArea;
                annotation.zip = placemark.postalCode;
  
                annotation.title = annotation.city;
                annotation.subtitle = annotation.state;
                [self.mapView addAnnotation:annotation];
            }

            if ([placemarks count] > 0) {
                MKPlacemark *lastPlacemark = (MKPlacemark *)placemarks.lastObject;
//这个方法可以设置mapView的显示范围(center, 米, 米)
                MKCoordinateRegion viewReign = MKCoordinateRegionMakeWithDistance(lastPlacemark.location.coordinate, 100, 100);
                [self.mapView setRegion:viewReign];
            }
    }];
3>. 大头针的代理方法
//当我们调用 [self.mapView addAnnotation:annotation];方法会来到这个方法
1. 使用系统大头针做的一些改变
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    //MKPinAnnotationView是系统默认的大头针数据模型 ,  这个跟tableView的重用的方式一样
    MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:@"PIN_ANNOTATION"];
    if (annotationView == nil) {
        annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"PIN_ANNOTATION"];
    }
    //是否弹出标注
    annotationView.canShowCallout = true;
    //设置大头针颜色
    annotationView.pinTintColor = [UIColor blackColor];
    //冲天而降
    annotationView.animatesDrop = true;
    
    return annotationView;
}

2. 自定义的大头针
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    static NSString *ID = @"PIN_ANNOTATION";
    MKAnnotationView *annotationView = (MKAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:ID];
    if (annotationView == nil) {
        annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ID];
    }
    //必须设置, 默认是不弹出标注
    annotationView.canShowCallout = true;
    //设置大头针为图片
    annotationView.image = [UIImage imageNamed:@"category_5"];
    UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
    iv.image = [UIImage imageNamed:@"htl"];
    
    annotationView.leftCalloutAccessoryView = iv;//标注的辅助视图
   
    annotationView.rightCalloutAccessoryView = iv;//标注的辅助视图
    
    annotationView.detailCalloutAccessoryView = [UISwitch new];//标注的辅助视图
    
    return annotationView;
}

//大头针选中的代理方法, 里面有对应的大头针的数据模型
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
    NSLog(@"纬度:%f----经度:%f", view.annotation.coordinate.latitude, view.annotation.coordinate.longitude);
    
}

- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
    NSLog(@"取消选中");
}

4>. 其他
    // 3D视角
//    MKMapCamera *camer = [MKMapCamera cameraLookingAtCenterCoordinate:CLLocationCoordinate2DMake(23.132931, 113.375924) fromEyeCoordinate:CLLocationCoordinate2DMake(23.135931, 113.375924) eyeAltitude:10];
//    self.mapView.camera = camer;
    
    //地图快照截图
    MKMapSnapshotOptions *option = [[MKMapSnapshotOptions alloc] init];
    // 针对地图
    option.region = self.mapView.region;
    option.showsBuildings = YES;
    
    // 输出图片
    option.size = CGSizeMake(1000, 2000);
    option.scale = [UIScreen mainScreen].scale;
    
    
    MKMapSnapshotter *snap = [[MKMapSnapshotter alloc] initWithOptions:option];
    
    [snap startWithCompletionHandler:^(MKMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
        
        if (error == nil) {
            UIImage *image = snapshot.image;
            
            NSData *data = UIImagePNGRepresentation(image);
            
            [data writeToFile:@"/Users/........" atomically:YES];
        }else
        {
            NSLog(@"--%@", error.localizedDescription);
        }
    }];
5>. 利用ios自带地图导航
//  ViewController.m
//  导航
//
//  Created by JasonBourne on 2018/5/4.
//  Copyright © 2018年 JasonBourne. All rights reserved.
//

#import "ViewController.h"
#import <MapKit/MapKit.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
    request.naturalLanguageQuery = @"荷兰";
    MKLocalSearch *search= [[MKLocalSearch alloc] initWithRequest:request];
    [search startWithCompletionHandler:^(MKLocalSearchResponse * _Nullable response, NSError * _Nullable error) {
        MKMapItem *lastmapItem = [response.mapItems lastObject];
        [lastmapItem openInMapsWithLaunchOptions:@{
                                                   // 导航方式
                                                   MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving,
                                                   
                                                   // 地图类型
                                                   MKLaunchOptionsMapTypeKey : @(MKMapTypeHybrid),
                                                   
                                                   // 是否显示交通
                                                   MKLaunchOptionsShowsTrafficKey : @(YES)
                                                   }];
    }];
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容