资料 | 汇总androidiOS Developer

LocationManager定位、地址搜索相关痛点解决(Bas

2017-02-24  本文已影响387人  dj_rose
地图选址

项目中对定位、地址搜索等功能采用了LocationManager单例模式,关于单例的优点在此就不赘述了,这里主要想分享一下单例模式下LocationManager的两个痛点。

首先简单贴一下单例的实现:

static LocationManger *locationInstance;
+(LocationManger*)getInstanceWithDelegate:(id)delegate
{
    @synchronized(self) {
        if (!locationInstance) {
            locationInstance = [[LocationManger alloc] init];
            locationInstance.geocoder = [[CLGeocoder alloc] init];
        }
        if (delegate) {
            locationInstance.delegate = delegate;
        }
    }
    return locationInstance;
}

当然,更推荐这样的写法:

static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
      //TO DO
    });

接下来,开始分析痛点:

痛点一

项目中某页面需要同时用到定位当前地址+对某坐标进行逆地理编码验证两个功能,高德回调函数难以区分。
当前地址的逻辑大致如下(非完整代码):

//发起定位
[self.lManager startUpdatingLocation];
//定位回调里拿到坐标->发起逆地理编码
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    ...
    //构造AMapReGeocodeSearchRequest对象,location为必选项,radius为可选项
    AMapReGeocodeSearchRequest *regeoRequest = [[AMapReGeocodeSearchRequest alloc] init];
    regeoRequest.location = [AMapGeoPoint locationWithLatitude:lItem.coordinate.latitude longitude:lItem.coordinate.longitude];
    regeoRequest.radius = 10000;
    regeoRequest.requireExtension = YES;
     [self.lManager stopUpdatingLocation];
     //发起逆地理编码
    [_search AMapReGoecodeSearch:regeoRequest];
}
//逆地理编码的回调函数->数据处理并回调相应VC
- (void)onReGeocodeSearchDone:(AMapReGeocodeSearchRequest *)request response:(AMapReGeocodeSearchResponse *)response
{
      //TO DO
}

总结下来定位当前地址的流程:
发起定位->定位回调里拿到坐标->发起逆地理编码-> 逆地理编码回调函数->数据处理并回调相应VC

而对某坐标进行逆地理编码验证则也是通过:
发起逆地理编码-> 逆地理编码回调函数->数据处理并回调相应VC

细心的同学已经发现了:两个不同的功能都会走同一个高德回调函数。这样就有可能造成区分不清对应关系的问题。

//构造AMapReGeocodeSearchRequest对象,location为必选项,radius为可选项
AMapReGeocodeSearchRequest *regeoRequest = [[AMapReGeocodeSearchRequest alloc] init];
[regeoRequest setValue:@"0" forKey:ReGeocodeSearchRequestKey];//标记为定位模式,回调里用于区分
AMapReGeocodeSearchRequest *regeoRequest = [[AMapReGeocodeSearchRequest alloc] init]; 
[regeoRequest setValue:@"1" forKey:ReGeocodeSearchRequestKey];//标记为地址验证模式,回调里用于区分

这样就能在逆地理回调里进行区分处理:

//实现逆地理编码的回调函数
- (void)onReGeocodeSearchDone:(AMapReGeocodeSearchRequest *)request response:(AMapReGeocodeSearchResponse *)response
{
    if(response.regeocode != nil)
    {
        NSString *bSearchAddress = [request valueForKey:ReGeocodeSearchRequestKey];
        //通过AMapReGeocodeSearchResponse对象处理搜索结果
        if ([bSearchAddress isEqualToString:@"1"]) {
            //地址验证模式
        }else {
            //定位模式
        }
    }
}
这里需要提一下,给对象动态绑定属性需要用到RunTime+Category:
#import "AMapReGeocodeSearchRequest+bSearchAddress.h"
#import <objc/runtime.h>

@implementation AMapReGeocodeSearchRequest (bSearchAddress)
@dynamic bSearchAddress;
static char str_bSearchAddress;

- (void)setBSearchAddress:(NSString *)bSearchAddress
{
    [self willChangeValueForKey:@"bSearchAddress"];
    objc_setAssociatedObject(self, &str_bSearchAddress, bSearchAddress, OBJC_ASSOCIATION_RETAIN);
    [self didChangeValueForKey:@"bSearchAddress"];
}

- (NSString *)bSearchAddress
{
    return objc_getAssociatedObject(self, &str_bSearchAddress);
}
@end

痛点二

同一页面有两处需要用到同一个地址搜索的功能,如何区分的问题。
在刚开始实现这个需求的时候,我还是很天真的在ViewController中用BOOL值去区分这两处的搜索,以期能在LocationManger回调给页面的方法里作区分。这个问题的解决方案应该更丰富一点,我最后是这么解决的:

- (void)startAMapKeyWordsSearchRequest:(AMapPOIKeywordsSearchRequest *)request;//高德地址搜索
#import <Foundation/Foundation.h>
#import "LocationManger.h"

@protocol RequestAddressObjectDelegate <NSObject>
- (void)requestKeywordsPOISuccess:(AMapPOISearchResponse *)response;
- (void)requestKeywordsPOIfailed:(NSString *)sError;
@end

@interface requestAddressObject : NSObject
<
LocationManagerDelegate
>
@property (weak, nonatomic) id<RequestAddressObjectDelegate> delegate;
@property (weak, nonatomic) LocationManger *locationManager;
@property (strong, nonatomic) AMapPOIKeywordsSearchRequest *requestKeywordsPlaceList;

- (void)requestPOIKeywordSearch:(AMapPOIKeywordsSearchRequest *)request;
- (void)requestPOIWithKeyword:(NSString *)keyword city:(NSString *)city cityLimit:(BOOL)cityLimit;

@end
#import "requestAddressObject.h"
@implementation requestAddressObject
- (LocationManger *)locationManager{
    if (!_locationManager) {
        _locationManager = [LocationManger getInstanceWithDelegate:self];
    }else {
        if (_locationManager.delegate != self) {
            _locationManager.delegate = self;
        }
    }
    return _locationManager;
}
- (void)requestPOIKeywordSearch:(AMapPOIKeywordsSearchRequest *)request
{
    [self.locationManager startAMapKeyWordsSearchRequest:request];
}
- (void)lmGetPOISearchDelegate:(AMapPOISearchResponse *)response
{
    if (self.delegate && [self.delegate respondsToSelector:@selector(requestKeywordsPOISuccess:)]) {
        [self.delegate requestKeywordsPOISuccess:response];
    }
}
- (void)lmGetLocationFaild:(NSString *)sError
{
    if (self.delegate && [self.delegate respondsToSelector:@selector(requestKeywordsPOIfailed:)]) {
        [self.delegate requestKeywordsPOIfailed:sError];
    }
}
@end
//ViewController中的第二处的处理

//懒加载
- (requestAddressObject *)reqAddressObj
{
    if (!_reqAddressObj) {
        _reqAddressObj = [[requestAddressObject alloc] init];
        _reqAddressObj.delegate = self;
    }
    return _reqAddressObj;
}

//第二处地址搜索的调用
[self.reqAddressObj requestPOIKeywordSearch:_requestKeywordsPlaceList];

//LocationManager的回调方法经由RequestAddressObject中转了一次之后回到VC的回调方法
#pragma mark - RequestAddressObjectDelegate
- (void)requestKeywordsPOISuccess:(AMapPOISearchResponse *)response
{
    //第二处地址搜索成功的回调
}

- (void)requestKeywordsPOIfailed:(NSString *)sError
{
    //第二处地址搜索失败的回调
}

输入选址
小结:两个小痛点都是如何对数据进行严格的区分问题。第一个是通过对request进行动态绑定属性来进行区分;第二个是通过用不同的请求方式(VC直接发起请求、间接通过object发起请求)来回避数据区分的问题。两个问题刚好是从不同的角度去解决问题,一个正面交锋;一个迂回战术。方案本无优劣,具体问题具体分析才是王道!
上一篇 下一篇

猜你喜欢

热点阅读