iOS 封装工具类 --代理模式转换block模式-定位
2015-11-12 本文已影响983人
iOS_成才录
一、需求
- 写个继承NSObject的工具类JPLocationTool,用block实现传值
二、具体实现
- 1.JPLocationTool.h文件
#import <Foundation/Foundation.h>
#import "Singleton.h"
#import <CoreLocation/CoreLocation.h>
typedef void(^ResultBlock)(CLLocation *location, CLPlacemark *pl, NSString *error);
@interface JPLocationTool : NSObject
single_interface(JPLocationTool);
- (void)getCurrentLocation:(ResultBlock)block;
@end
- 2.JPLocationTool.m文件
#import "JPLocationTool.h"
#import <UIKit/UIKit.h>
#define isIOS(version) ([[UIDevice currentDevice].systemVersion floatValue] >= version)
@interface JPLocationTool()<CLLocationManagerDelegate>
/** 回调代码块 */
@property (nonatomic, copy) ResultBlock block;
/** 位置管理者 */
@property (nonatomic, strong) CLLocationManager *locationM;
/** 地理编码 */
@property (nonatomic, strong) CLGeocoder *geoC;
@end
@implementation JPLocationTool
single_implementation(JPLocationTool);
#pragma mark -懒加载
-(CLLocationManager *)locationM
{
if (!_locationM) {
_locationM = [[CLLocationManager alloc] init];
_locationM.delegate = self;
// iOS8.0之后, 必须手动请求定位授权
// 获取info.plist 里面的键值对
NSDictionary *infoDic = [NSBundle mainBundle].infoDictionary;
// NSLog(@"%@", infoDic);
if (isIOS(8.0)) {
// [_locationM requestAlwaysAuthorization];
// [_locationM requestWhenInUseAuthorization];
// 获取前后台定位描述(看其他开发者到底有没有添加这个key)
NSString *alwaysStr = infoDic[@"NSLocationAlwaysUsageDescription"];
// 获取前后台定位描述(看其他开发者到底有没有添加这个key)
NSString *whenInUseStr = infoDic[@"NSLocationWhenInUseUsageDescription"];
// 判断其它开发者, 到底填写的是哪个key
if([alwaysStr length] > 0)
{
[_locationM requestAlwaysAuthorization];
}
else if ([whenInUseStr length] > 0)
{
[_locationM requestWhenInUseAuthorization];
// 如果请求的是前台定位授权, 如果想要在后台获取用户位置, 提醒其他开发者, 勾选后台模式location updates
NSArray *backModes = infoDic[@"UIBackgroundModes"];
if (![backModes containsObject:@"location"]) {
NSLog(@"当前授权模式是前台定位授权, 如果想要在后台获取位置, 需要勾选后台模式location updates");
}else // 代表当前勾选后台模式, 而且是前台定位授权
{
if(isIOS(9.0))
{
_locationM.allowsBackgroundLocationUpdates = YES;
}
}
}else
{
NSLog(@"如果在iOS8.0之后获取用户位置, 必须主动填写info.plist文件中的key NSLocationAlwaysUsageDescription 或者 NSLocationWhenInUseUsageDescription");
}
}else // ios8.0之前
{
// 如果请求的是前台定位授权, 如果想要在后台获取用户位置, 提醒其他开发者, 勾选后台模式location updates
NSArray *backModes = infoDic[@"UIBackgroundModes"];
if (![backModes containsObject:@"location"]) {
NSLog(@"当前授权模式, 如果想要在后台获取位置, 需要勾选后台模式location updates");
}
}
}
return _locationM;
}
#pragma mark -懒加载
-(CLGeocoder *)geoC
{
if (!_geoC) {
_geoC = [[CLGeocoder alloc] init];
}
return _geoC;
}
- (void)getCurrentLocation:(ResultBlock)block
{
// 记录代码块
self.block = block;
// 获取用户位置信息
if([CLLocationManager locationServicesEnabled])
{
[self.locationM startUpdatingLocation];
}else
{
self.block(nil, nil, @"定位服务未开启");
}
}
#pragma mark -CLLocationManagerDelegate
/**
* 定位到之后调用
*
* @param manager 位置管理者
* @param locations 位置数组
*/
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
CLLocation *location = [locations lastObject];
// 判断位置是否可用
if (location.horizontalAccuracy >= 0) {
[self.geoC reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
if (error == nil) {
CLPlacemark *pl = [placemarks firstObject];
self.block(location, pl, nil);
}else
{
self.block(location, nil, @"反地理编码失败");
}
}];
}
// 如果只需要获取一次位置, 那么在此处停止获取用户位置
[manager stopUpdatingLocation];
}
/**
* 当前授权状态发生改变时调用
*
* @param manager 位置管理者
* @param status 状态
*/
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status) {
// 用户还未决定
case kCLAuthorizationStatusNotDetermined:
{
NSLog(@"用户还未决定");
break;
}
// 问受限
case kCLAuthorizationStatusRestricted:
{
NSLog(@"访问受限");
self.block(nil, nil, @"访问受限");
break;
}
// 定位关闭时和对此APP授权为never时调用
case kCLAuthorizationStatusDenied:
{
// 定位是否可用(是否支持定位或者定位是否开启)
if([CLLocationManager locationServicesEnabled])
{
NSLog(@"定位开启,但被拒");
self.block(nil, nil, @"被拒绝");
}else
{
NSLog(@"定位关闭,不可用");
self.block(nil, nil, @"定位关闭,不可用");
}
break;
}
// 获取前后台定位授权
case kCLAuthorizationStatusAuthorizedAlways:
// case kCLAuthorizationStatusAuthorized: // 失效,不建议使用
{
NSLog(@"获取前后台定位授权");
break;
}
// 获得前台定位授权
case kCLAuthorizationStatusAuthorizedWhenInUse:
{
NSLog(@"获得前台定位授权");
break;
}
default:
break;
}
}
@end
- 3.使用:获取定位信息与地标对象
#import "ViewController.h"
#import "JPLocationTool.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[[JPLocationTool sharedJPLocationTool] getCurrentLocation:^(CLLocation *location, CLPlacemark *pl, NSString *error) {
if([error length] > 0)
{
NSLog(@"有错误--%@", error);
}else
{
NSLog(@"%@", pl.name);
}
}];
}
@end
三、依赖的单例宏 Singleton.h
// .h
#define single_interface(class) + (class *)shared##class;
// .m
// \ 代表下一行也属于宏
// ## 是分隔符
#define single_implementation(class) \
static class *_instance; \
\
+ (class *)shared##class \
{ \
if (_instance == nil) { \
_instance = [[self alloc] init]; \
} \
return _instance; \
} \
\
+ (id)allocWithZone:(NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [super allocWithZone:zone]; \
}); \
return _instance; \
}