LocationManager - 实现自定义封装定位类
相信很多app都需要用到定位这个功能,不知道大家写的时候有没有遇到这个问题:
LocationManager的代理方法在控制器中写的话可以进入,但是当自己自定义封装成一个类写成shareManager的时候,就不会进代理方法。
反复断点调试,发现shareManager是初始化了两次,此时猜想,可能是两个LocationManager的shareManager对象不一样,第二个把第一个覆盖了。
最后的解决方法是将shareManager用线程锁保证唯一性,终于可以进入代理方法。
在以后的shareManager中,应当保证其唯一性,再进行操作。
下面是代码:
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
typedef void (^SaveLocationCallback) (NSString *cityName);
@interface LocationManager : NSObject<CLLocationManagerDelegate> {
CLLocationManager *_manager;
SaveLocationCallback _saveLocationCallback;
}
//获取定位城市名称
+ (void) getCityName:( SaveLocationCallback )cb;
//停止定位
+ (void) stop;
@end
#import "LocationManager.h"
@implementation LocationManager
+ (id) sharedGpsManager {
static id s;
static dispatch_once_t token;
dispatch_once(&token, ^{
s = [[LocationManager alloc] init];
});
return s;
}
- (id)init {
self = [super init];
if (self) {
// 打开定位 然后得到数据
_manager = [[CLLocationManager alloc] init];
_manager.delegate = self;
_manager.desiredAccuracy = kCLLocationAccuracyBest;
_manager.distanceFilter = kCLDistanceFilterNone;
float osVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (osVersion >= 8) {
[_manager requestWhenInUseAuthorization];
}
}
return self;
}
- (void) getCityName:(SaveLocationCallback)cb {
if (![CLLocationManager locationServicesEnabled]) {
return;
}
// block赋值
_saveLocationCallback = [cb copy];
// 停止上一次,开始新的数据定位
[_manager stopUpdatingLocation];
[_manager startUpdatingLocation];
}
//获取定位
+ (void) getCityName:(SaveLocationCallback)cb {
[[LocationManager sharedGpsManager] getCityName:cb];
}
//结束定位
- (void) stop {
[_manager stopUpdatingLocation];
}
+ (void) stop {
[[LocationManager sharedGpsManager] stop];
}
#pragma mark - locationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLGeocoder *geoCoder = [[CLGeocoder alloc]init];//反向解析,根据及纬度反向解析出地址
CLLocation *location = [locations objectAtIndex:0];
[geoCoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
for(CLPlacemark *place in placemarks)
{
NSDictionary *dict = [place addressDictionary];
if (_saveLocationCallback) {
_saveLocationCallback(dict[@"City"]);
}
}
}];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error{
switch([error code])
{
case kCLErrorNetwork: // general, network-related error
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Please check your network connection or that you are not in airplane mode" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
break;
case kCLErrorDenied:{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"User has denied to use current Location " delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
break;
default:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Unknown network error" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
break;
}
}
}
这里我们也需要关注一下locationManager:(CLLocationManager *)manager didFailWithError方法,error.code
kCLErrorNetwork网络错误
kCLErrorDenied用户拒绝访问(本来我以为
[CLLocationManager locationServicesEnabled]会
判断出来,但是,在给予了授权之后,用户手动关闭app获取位置的权限,就会触发这个错误。)