IOS 高德地图 Block使用工具类 YGaoDeMapUtils

GitHub地址

https://github.com/LiZunYuan/YGaoDeMapUtils(兼容IOS6 以上)

因项目中多地方使用高德地图,而高德地图本身是使用代理的形式回调。使得调用很麻烦,帮自己写了个高德地图的工具类,采用了Block的方式。

在项目中遇到最大的问题是,如何把当前的类不借且多余的代码使得生命周期可以完整走完再结束。就像调用UIAlterView一样,从来不用自己写addSubView什么的,只要show即可。我想UIAlterView其实是自己从全局的[UIApplication sharedApplication] 上获得Window上,所以对于使用者,不需要多写代码。而我想利用objc的runtime机制做到一样的简单使用。

使用方法

首先设置下高德的Key(需要到高德官网绑定下 传送门
[YGaoDeMapUtils setApiKey:@"apiKey"];

1.仅获得用户当前位置的经纬度(方法执行很快,不需要请求网络)

[YGaoDeMapUtils getUserCurrentLocationInfoSuccessBlock:^(YLocationInfo *yLocationInfo) {
    NSLog(@"1查");
} failure:^(NSError *error) {
    NSLog(@"1%@",error);
}];

2.获得用户经纬度之外 再获得额外信息,如地区编码,城市等信息 RequireExtension 参数设置YES 可以获得更多

[YGaoDeMapUtils getUserCurrentLocationMoreInfoRequireExtension:NO successBlock:^(YLocationInfo *yLocationInfo) {
    NSLog(@"2查");
} failure:^(NSError *error) {
    NSLog(@"2%@",error);
}];

3.该查询功能根据关键字,查询该关键字所匹配的兴趣点信息

[YGaoDeMapUtils queryPoiByKeyword:@"后海" cityInfo:@"北京" requireExtension:YES successBlock:^(NSArray *poiArray) {
    NSLog(@"4查");
} failure:^(NSError *error) {
    NSLog(@"4%@",error);
}];

5.根据地址信息查询

[YGaoDeMapUtils queryLocationInfoWithAddressName:@"瑞博国际" successBlock:^(YLocationInfo *yLocationInfo) {
    NSLog(@"5查%@",yLocationInfo);
} failure:^(NSError *error) {
    NSLog(@"5%@",error);
}];

6.该查询可以实现以某一地理坐标点为圆心,指定半径和指定关键字附近的兴趣点信息

[YGaoDeMapUtils queryPoiByAroundWithLatitude:@"30" andLongitude:@"120" cityInfo:@"北京" requireExtension:YES successBlock:^(NSArray *poiArray) {
    NSLog(@"6查");
} failure:^(NSError *error) {
    NSLog(@"6%@",error);
}];

原理

在这个工具类中,并不是一个view,而只是一个简单的对象。于是我想到的是采用objc的runtime 机制。当想要初始化的时候将对象保存在[UIApplication sharedApplication].delegate(其实可以是任意APP生命周期中都存在的任意对象)中,代码如下:

先定位一个静态变量

static char gaoDeMapToolArrayKey;

然后利用runtime机制设置值

objc_setAssociatedObject([UIApplication sharedApplication].delegate, &gaoDeMapToolArrayKey, gaoDeMapToolArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

gaoDeMapToolArray 是一个可变数组,用于保存各个不同的定位代码的冲突。当数据都保存好后,遇到block事件结束应该结束生命周期。如何解除生命周期呢,就是把对象从[UIApplication sharedApplication].delegate移除掉。网上有很多方法比如:objc_removeAssociatedObjects但这个方法会解除所有的属性关联,如果其它库或者代码写了相同的属性在delegate上,就会产生问题,于是我采用的是:

    objc_setAssociatedObject([UIApplication sharedApplication].delegate, &gaoDeMapToolArrayKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

其实就是把对象置空掉,事实证明,可行。因为对象走到了dealloc上了。

遇到的问题

1.之前在使用objc_setAssociatedObject的时候,保存的只是一个对象(非数组),导致写两个定位的方法时,就会把上一个定位的对象消除。纠结了蛮久,也想过设置多个静态变量来分别处理。后来也觉得不妥。最终就想到了利用数组来设置。在释放完检查数组的长度,如果数组长度为0了,就把数组这个属性也移除。

2.利用Xcode6新建的代码,发现在IOS6设备上并不能出现定位授权的提示,查找了半天,甚至把以前的代码拷贝过来也是不行。最终发现在Info.plist中少了Bundle display name添加上就好了。