使用Category+runtime简单解决高德地图定位问题

项目背景介绍 项目需求 :使用定位功能,获取当前用户所在的地区 打算使用的定位框架 : 高德定位 平台 : iOS && Android

image.png

高德API


手把手使用步骤简介(cocopods版本): 1.创建pod文件,添加pod 'AMapLocation',执行podinstall

pod install.png

2.申请高德appKey ( 高德Key申请 )

申请高德Key.png

3.打开私有权限-定位权限

info.plist - 定位权限

4.代码模块

  • appdelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    //使用自己申请的定位apiKey替换
    [AMapServices sharedServices].apiKey = @"f84c62976e2e415b86c70dbd95793f4e";
    
    return YES;
}
  • 在需要定位的控制器 viewController.m
- (void)viewDidLoad
{
    self.view.backgroundColor = [UIColor orangeColor];

    _locationManager = [[AMapLocationManager alloc]init];
    
    [_locationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers];
    //   定位超时时间,最低2s,此处设置为10s
    _locationManager.locationTimeout =10;
    //   逆地理请求超时时间,最低2s,此处设置为10s
    _locationManager.reGeocodeTimeout = 10;
    // 带逆地理(返回坐标和地址信息)。将下面代码中的 YES 改成 NO ,则不会返回地址信息。
    [_locationManager requestLocationWithReGeocode:YES completionBlock:^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error) {
        
        if (error)
        {
            //定位失败
            NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription);
            
            if (error.code == AMapLocationErrorLocateFailed)
            {
                return;
            }
        }
        NSLog(@"location:%@", location);
        
        if (regeocode)
        {
            //定位成功-打印详细信息
            NSLog(@"reGeocode:%@", regeocode);
        }
    }];
    
}

CLLocationAccuracy - 定位选择 // 最准确的定位,浪费时间最长 kCLLocationAccuracyBest // 比较准确的定位(10米误差) kCLLocationAccuracyNearestTenMeters // 相对准确的定位(100米误差) kCLLocationAccuracyHundredMeters; // 相对准确的定位(1千米误差) kCLLocationAccuracyKilometer; // 最不准确的定位(3千米误差) kCLLocationAccuracyThreeKilometers; 根据自己的需求选择定位类型,越精准的,越耗时

效果演示:

定位成功演示.png

前方高能,坑即将出现

  • demo示例中,每个控制器都得写一个@property (nonatomic, strong) AMapLocationManager *locationManager;,然后用成员变量 _locationManager 进行定位操作
  • 如果有两个(或多个)控制器可能用到定位功能,岂不是每个地方都要写这么多代码?
  • 思考封装,将整个定位模块封装到外部
  • 隔离代码依赖的_locationManager属性
- (void)viewDidLoad
{
    self.view.backgroundColor = [UIColor orangeColor];

    //这里不用_locationManager,不声明locationManager属性,new一个新的AMapLocationManager
    AMapLocationManager *locationManager = [AMapLocationManager manager];

    [locationManager requestLocationWithReGeocode:YES completionBlock:^(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error) {
        
        if (error)
        {
            NSLog(@"locError:{%ld - %@};", (long)error.code, error.localizedDescription);
            
            if (error.code == AMapLocationErrorLocateFailed)
            {
                return;
            }
        }
        NSLog(@"location:%@", location);
        
        if (regeocode)
        {
            NSLog(@"reGeocode:%@", regeocode);
        }
    }];
}

没有声明属性的AMapLocationManager

解决办法 :使用分类

思路:

  • 因为测试得知,一点得使用属性,又不想每个需要的控制器都声明locationManager属性,所以打算建一个 UIViewController的分类,所有的viewController都能拿到locationManager属性
  • 所有的代理&&属性之类定位所需要的必要元素,写到分类中,使用的控制器不需要import定位文件 && 设置定位代理。。。
  • 暴露一个调用方法在外部,需要用的控制器,调用分类的方法即可,方便复用

UIviewController分类.h部分代码

分类.m文件警告

手动声明locationManager属性.png

分类方法调用失败.png

解决办法

  • 使用runtime的关联对象
  • 为分类添加属性
static void *managerKey = &managerKey;

-(void)setLocationManager:(AMapLocationManager *)locationManager{
    objc_setAssociatedObject(self, managerKey, locationManager, OBJC_ASSOCIATION_RETAIN);
}

-(AMapLocationManager *)locationManager{
    return objc_getAssociatedObject(self, managerKey);
}

image.png

进阶需求

image.png

  • 例如demo中的,section=2,row=0的地方,要使用定位功能,获取到定位地址之后,又要把内容显示到界面上
//启动定位 - 并赋值
- (void)startLocationSetModel:(GaodeModel *)model LocationBlock:(LocationBlock)locationBlock;

image.png

总结:

  • 使用UIViewController 分类,解决当前高德API定位必须依赖locationManager属性的问题
  • 使用runtime的关联对象,为分类的locationManager属性赋值(set && get方法)
  • locationManager的创建,也可以使用分类,使用AMapLocationManager+MNExt.h 自定义快速创建 locationManager的方法
  • 主要代码都封装在外部,需要用到的控制器,只要import分类 + 使用分类的方法,一句代码搞定定位需求
  • 如果有需要定位之后为模型赋值的,我新增了一个回调函数,可以在- (void)startLocationSetModel:(GaodeModel *)model LocationBlock:(LocationBlock)locationBlock中实现需求
  • 如果有其他的需求的,可以在此基础上进行拓展、修改

demo

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏進无尽的文章

实践-做一个会性能调优的好猿

对于每位 iOS 开发者来说,代码性能是个避不开的话题。随着项目的扩大和功能的增多,没经过认真调试和优化的代码,要么任性地卡顿运行,要么低调地崩溃。一般性能测试...

822
来自专栏有刻

Mac 小记 — 杂录

3706
来自专栏java一日一条

高效Android开发者必须知道的4个工具

移动app开发是一个漫长而费力的过程。然而,现在的企业总是希望能够尽快发布app。幸运的是,我们有很多帮助移动开发人员加快工作步伐的工具。

1371
来自专栏软件开发 -- 分享 互助 成长

Altium designer总结

大概有半年没有画过PCB板了,最近突然又要画一个简单的小板子,却发现好多东西已经不是很熟练了,现在把Altium designer软件的使用中要注意的问题和一些...

24610
来自专栏谦谦君子修罗刀

程序员面试闪充 -- 性能优化

CPU 和GPU 关于绘图和动画有两种处理方式CPU(中央处理器)和GPU(图形处理器),CPU的工作都在软件层面,而GPU的在硬件层面。 总的来说,可以使用...

39213
来自专栏魏艾斯博客www.vpsss.net

屏幕 GIF 动态图捕获软件及录制过程

作为站长有时候需要录制屏幕 GIF 动态图片,就得现学现卖。这不魏艾斯博客在使用遨游浏览器的过程中遇到一些 bug 需要提交给官方,遨游技术员希望老魏提供一段正...

2402
来自专栏ionic3+

【Appetite】ionic3实录(六)首页实现

观察之,发布者和内容的文本信息可以用ionic现有的组件实现,而视频播放和图片画廊(如果是轮播图可以用slides组件,它是阉割并封装过的swiper,好像现在...

1004
来自专栏维C果糖

设置 IntelliJ IDEA 主题和字体的方法

1 前言 在博文「IntelliJ IDEA 之 HelloWorld 项目创建及相关配置文件介绍」中,我们已经用 IntelliJ IDEA 创建了第一个 J...

95610
来自专栏java一日一条

高效Android开发者必须知道的4个工具

移动app开发是一个漫长而费力的过程。然而,现在的企业总是希望能够尽快发布app。幸运的是,我们有很多帮助移动开发人员加快工作步伐的工具。

1093
来自专栏Phoenix的Android之旅

如何加载一张超大高清图

"大图片加载容易做,可是这个需求要保证在不OOM的情况下能放大查看,还要能清晰展示,这得怎么呢?",愁眉苦脸的小呼说到。

942

扫码关注云+社区

领取腾讯云代金券