鑒于地理位置的獲取是異步的,所以在獲取地理位置信息之后再通知當(dāng)前用戶使用,就封裝了下。
需要導(dǎo)入的頭文件:
import <CoreLocation/CoreLocation.h>
涉及到的類
CCLocation
CClocationManager
CCLocationManager像個(gè)坐標(biāo)的管理者。CCLocation可以理解為對(duì)坐標(biāo)的一些信息的封裝。
封裝的文件
.h文件
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
NS_ASSUME_NONNULL_BEGIN
/**
地理位置獲取之后的回調(diào)block
@param isAuthorized 是否授權(quán)
@param coordinate 獲取CLLocation的屬性coordinate坐標(biāo)信息,是個(gè)結(jié)構(gòu)體,內(nèi)部包含經(jīng)緯度。當(dāng)為kCLLocationCoordinate2DInvalid表示未定位
@param error 定位失敗時(shí)返回的信息,成功時(shí)為nil
*/
typedef void(^LocationCallBackWithCoordinateBlock) (BOOL isAuthorized,CLLocationCoordinate2D coordinate , NSError * _Nullable error);
/**
地理位置獲取之后的回調(diào)block
@param isAuthorized 是否授權(quán)
@param location 獲取的CLLocation,失敗時(shí)為nil
@param error 定位失敗時(shí)返回的信息,成功時(shí)為nil
*/
typedef void(^LocationCallBackWithLocationBlock) (BOOL isAuthorized,CLLocation * _Nullable location , NSError * _Nullable error);
@interface RainLocationKit : NSObject
/**
請(qǐng)求對(duì)地理位置獲取的授權(quán)
第一次創(chuàng)建kit對(duì)象時(shí),會(huì)做授權(quán)操作,授權(quán)結(jié)束后我們會(huì)去做一次定位。但是授權(quán)結(jié)束后,不會(huì)再去做定位了。如果再想拿同一個(gè)對(duì)象獲取獲取定位信息,請(qǐng)使用開始定位來獲取
*/
- (void)requestLocationAuthorized;
/**
開啟地理位置獲取,并且傳遞地理位置獲取成功后的回調(diào)block
因?yàn)榈乩砦恢玫墨@取是異步的,所以等拿到數(shù)據(jù)之后再上傳
@param locationCallBack 地理位置獲取成功后的回調(diào)
*/
- (void)startUpdateLocationWithCoordinateCompletion:(LocationCallBackWithCoordinateBlock) locationCallBack;
- (void)startUpdateLocationWithLocationCompletion:(LocationCallBackWithLocationBlock) locationCallBack;
/**
設(shè)置定位成功之后回調(diào),通過回調(diào)獲取數(shù)據(jù)
@param locationCallBack 回調(diào)block
*/
- (void)setLocationCallbackBlock:(LocationCallBackWithCoordinateBlock) locationCallBack;
- (void)setLocationWithLocationCallBackBlock:(LocationCallBackWithLocationBlock) locationCallBack;
/**
開始更新定位信息。當(dāng)授權(quán)完成之后,仍然使用當(dāng)前定位對(duì)象時(shí),可以使用該方法更新定位數(shù)據(jù)
*/
- (void)startUpdateLocation;
@end
NS_ASSUME_NONNULL_END
.m文件
#import "RainLocationKit.h"
@interface RainLocationKit()<CLLocationManagerDelegate>
@property (nonatomic, strong, readonly)CLLocationManager *locationManager;
@property (nonatomic, strong, readonly)CLLocation *location;
@property (nonatomic, copy)LocationCallBackWithCoordinateBlock locationCallbackBlock;
@property (nonatomic, copy)LocationCallBackWithLocationBlock locationWithLocationCallBackBlock;
@end
@implementation RainLocationKit
@synthesize locationManager = _locationManager;
@synthesize location = _location;
- (void)startUpdateLocationWithCoordinateCompletion:(LocationCallBackWithCoordinateBlock) locationCallBack {
self.locationCallbackBlock = locationCallBack;
[self requestLocationAuthorized];
}
- (void)startUpdateLocationWithLocationCompletion:(LocationCallBackWithLocationBlock) locationCallBack {
self.locationWithLocationCallBackBlock = locationCallBack;
[self requestLocationAuthorized];
}
- (void)startUpdateLocation {
if ([self canUseLocation]) {
[self.locationManager startUpdatingLocation];
}else {
if (self.locationCallbackBlock) {
self.locationCallbackBlock(NO, kCLLocationCoordinate2DInvalid, nil);
}
if (self.locationWithLocationCallBackBlock) {
self.locationWithLocationCallBackBlock(NO, nil, nil);
}
}
}
- (void)requestLocationAuthorized {
if ([CLLocationManager locationServicesEnabled]) {
if(@available(iOS 8.0,*)) {
[self.locationManager requestWhenInUseAuthorization];
}
}else {
#ifdef DEBUG
NSLog(@"地理位置服務(wù)不可用");
#endif
if (self.locationCallbackBlock) {
self.locationCallbackBlock(NO, kCLLocationCoordinate2DInvalid, nil);
}
if (self.locationWithLocationCallBackBlock) {
self.locationWithLocationCallBackBlock(NO, nil, nil);
}
}
}
/**
是否可以使用定位
即授權(quán)未拿到或者未定義plist文件里的授權(quán)描述
info.plist里需要定義的兩個(gè)key-value信息如下:
<key>NSLocationAlwaysUsageDescription</key>
<string>我們將使用你的位置為你提供就近咨詢和信息服務(wù)</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>我們將使用你的位置為你提供就近咨詢和信息服務(wù)</string>
@return YES表示可以使用,NO表示不可以使用,
*/
- (BOOL)canUseLocation {
if (![CLLocationManager locationServicesEnabled]) {
return NO;
}
if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedAlways &&
[CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) {
return NO;
}
return YES;
}
#pragma mark- CLLocationManagerDelegate
/**
授權(quán)狀態(tài)變更代理回調(diào)
@param manager 位置管理器
@param status 狀態(tài)值
*/
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
NSString *message = nil;
switch (status) {
case kCLAuthorizationStatusAuthorizedAlways:
[self startUpdateLocation];
message = @"一直使用地理位置";
break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
[self startUpdateLocation];
message = @"使用期間使用地理位置";
break;
case kCLAuthorizationStatusDenied:
message = @"用戶禁用地理位置訪問服務(wù)";
break;
case kCLAuthorizationStatusRestricted:
message = @"系統(tǒng)定位服務(wù)功能被限制";
break;
case kCLAuthorizationStatusNotDetermined:
message = @"用戶未決定地理位置的使用";
break;
default:
break;
}
#ifdef DEBUG
NSLog(@"地理位置授權(quán)狀態(tài)變化:%@", message);
#endif
}
/*
獲取到了定位數(shù)據(jù)
*/
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
_location = [locations lastObject];
#ifdef DEBUG
NSLog(@"經(jīng)緯度可能會(huì)獲取多次");
NSLog(@"緯度 = %f", _location.coordinate.latitude);
NSLog(@"經(jīng)度 = %f", _location.coordinate.longitude);
#endif
[self.locationManager stopUpdatingLocation];
if (self.locationCallbackBlock) {
self.locationCallbackBlock(YES, _location.coordinate, nil);
}
if (self.locationWithLocationCallBackBlock) {
self.locationWithLocationCallBackBlock(YES, _location, nil);
}
}
/*
*定位失敗
*/
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
#ifdef DEBUG
NSLog(@"定位失敗 error: %@", [error description]);
#endif
if (self.locationCallbackBlock) {
self.locationCallbackBlock(YES, kCLLocationCoordinate2DInvalid, error);
}
if (self.locationWithLocationCallBackBlock) {
self.locationWithLocationCallBackBlock(YES, nil, error);
}
}
#pragma mark- getter
- (CLLocationManager *)locationManager {
if (_locationManager == nil) {
_locationManager = CLLocationManager.new;
_locationManager.delegate = self;
///期望的精準(zhǔn)度。有五個(gè)選項(xiàng)值。我們使用的是最好精度
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
///刷新距離
_locationManager.distanceFilter = 10;
}
return _locationManager;
}
- (void)setLocationCallbackBlock:(LocationCallBackWithCoordinateBlock) locationCallBack {
_locationCallbackBlock = locationCallBack;
}
- (void)setLocationWithLocationCallBackBlock:(LocationCallBackWithLocationBlock) locationCallBack {
_locationWithLocationCallBackBlock = locationCallBack;
}
@end
解釋說明
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status這個(gè)方法里能獲取到用戶對(duì)地理位置信息的授權(quán)狀態(tài)。但是授權(quán)過程并不會(huì)中斷[self.locationManager startUpdatingLocation];啟動(dòng)定位的執(zhí)行。因?yàn)樘幱谑跈?quán)過程中,所以定位沒有結(jié)果。導(dǎo)致第一次授權(quán)啟動(dòng)定位失敗,下次定位沒問題。為了解決這個(gè)問題。我們?cè)谑跈?quán)狀態(tài)變成可用狀態(tài)才進(jìn)行定位的。即這段代碼

授權(quán)后定位.png
。
另外再次獲取定位信息時(shí)只需要
[self.locationManager startUpdatingLocation];或者[self startUpdateLocation];就可以了。