iOS CLLocationManager 地理定位

鑒于地理位置的獲取是異步的,所以在獲取地理位置信息之后再通知當(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];就可以了。

更新時(shí)間2018-11-27

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容