美文网首页iOS学习专题iOS Development程序员
使用Category+runtime简单解决高德地图定位问题

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

作者: 小蠢驴打代码 | 来源:发表于2018-02-11 15:26 被阅读90次

    项目背景介绍

    项目需求 :使用定位功能,获取当前用户所在的地区
    打算使用的定位框架 : 高德定位
    平台 : 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

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/hvyktftx.html