iOS实现模拟定位功能的示例代码
前言
App中越来越多的功能依赖用户实际的位置,例如基于用户位置提供推荐数据、基于定位判断某些功能是否可用,但是在开发调试中XCode却没有提供自定义的模拟定位的功能,所以本文主要的目的是现实一个可以在开发调试过程中随时模拟定位的功能。
思路
我们在iOS的app开发中通常采用的是CLLocationManager来获取用户当前的位置,当然也可以采用MKMapView的showUserLocation来获取用户的位置,所以我们分别针对这两种情况分析。
CLLocationManager
采用CLLocationManager获取定位时,是根据CLLocationManagerDelegate中-(void)locationManager:(CLLocationManager*)manager didUpdateLocations:(NSArray
1、Runtimeswizzle
因为业务代码是根据-(void)locationManager:(CLLocationManager*)manager didUpdateLocations:(NSArray
- 优点:便于理解。
- 缺点:需要遍历所有的类和类的方法列表。
2、中间代理对象
这种思路是Swizzle了CLLocationManager的setDelegate:方法,当调用setDelegate时,将真实的delegateobject保存下来,再将我们定义的中间代理类swizzledelegate对象设置为CLLocationManager的delegate,这样当系统回调CLLocationManagerDelegate,会先回调到中间代理类swizzledelegate中,再由swizzledelegate将事件传递到真实的delegateobject。
- 优点:相对于第一种方法,不需要遍历类和类的方法列表,只需swizzleCLLocationManager中的setDelegate:方法即可。
- 缺点:在中间代理类swizzledelegate中需要实现全部的CLLocationManagerDelegate方法,如果后续增加代理方法,仍需要修改这个类。
3、采用NSProxy实现中间代理对象
Objective-C中有2个基类,常用的就是NSObject,另一个就是NSProxy,NSProxy主要用于消息转发处理,所以采用NSProxy我们可以更好的处理方法二中的缺点。
3.1创建一个新的类MockLocationProxy,集成自NSProxy。
//MockLocationProxy.h #import@interfaceMockLocationProxy:NSProxy @property(nonatomic,weak,readonly,nullable)id target; -(instancetype)initWithTarget:(id )target; @end
//MockLocationProxy.m #import"MockLocationProxy.h" @implementationMockLocationProxy -(instancetype)initWithTarget:(id)target{ _target=target; returnself; } @end
接着就来处理消息转发的逻辑,首先我们要知道我们想要的是什么效果,系统回调给MockLocationProxy,MockLocationProxy只处理locationManager:didUpdateLocations:,其他的消息都仍然交给原target。
所以我们在MockLocationProxy.m中添加以下方法:
//MockLocationProxy.m @implementationMockLocationProxy -(instancetype)initWithTarget:(id)target{ _target=target; returnself; } -(BOOL)respondsToSelector:(SEL)aSelector{ if(aSelector==@selector(locationManager:didUpdateLocations:)){ returnYES; } return[self.targetrespondsToSelector:aSelector]; } -(void)forwardInvocation:(NSInvocation*)invocation{ SELsel=invocation.selector; if([self.targetrespondsToSelector:sel]){ [invocationinvokeWithTarget:self.target]; } } -(NSMethodSignature*)methodSignatureForSelector:(SEL)sel{ return[self.targetmethodSignatureForSelector:sel]; } #pragmamark-CLLocationManagerDelegate -(void)locationManager:(CLLocationManager*)managerdidUpdateLocations:(NSArray *)locations{ if([self.targetrespondsToSelector:_cmd]){ //模拟定位代码 CLLocation*mockLocation=[[CLLocationalloc]initWithLatitude:39.908722longitude:116.397499]; locations=@[mockLocation]; [self.targetlocationManager:managerdidUpdateLocations:locations]; } } @end
当消息发送给MockLocationProxy时,判断当前方法是否是locationManager:didUpdateLocations:,如果是,则MockLocationProxy响应事件,否则直接传递给原本的target。到此已经可以随时处理模拟定位。你只需要在模拟定位的代码做一些处理,就可以随时修改定位。
Onemore.
上述方法虽然可以模拟定位,但是每次修改模拟值都需重新build,那么有没有办法在运行时随时修改这个值呢?
LLDebugTool
当然可以,你只需要在你的项目中集成LLDebugTool,调用其中的Location模块,LLDebugTool提供了一个UI来随时修改这个模拟值,让你在调试时,随时模拟定位,LLDebugTool仍提供了很多其他的功能,如果你只需要模拟定位的功能,则只需要集成LLDebugTool/Location这个subspec就可以了。
后记
前言说过,定位除了CLLocationManager之外,MKMapView的showUserLocation也可以获取定位信息,那么如何解决这个问题呢?你可以在LLDebugTool/Location中查看答案。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。