简介 在移动互联网时代,移动 app 能解决用户的和诺生活琐事,比如:
周边:找参观,找 KTV、找电影院等等
导航:根据用户设定的起点和中点,进行路线桂法,并指引用户如何到达
在上述应用中,都用到了定位和地图功能,在 iOS 开发中,要想加入这两大功能,必须基于2个框架进行开发
CoreLocation:用于地理定位,地理编码,区域监听等(着重功能实现)
地理编码:将详细地址转换成经纬度
2个热门专业术语
LBS:Location Based Service
CoreLocation在 iOS8.0之前的简单实用 使用须知:
注意:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 -  (CLLocationManager  *)locationManager {     if  (_locationManager == nil ) {                  _locationManager = [[CLLocationManager  alloc] init];         _locationManager.delegate = self ;                           _locationManager.distanceFilter = 100 ;                                                      _locationManager.desiredAccuracy = kCLLocationAccuracyBest;     }     return  _locationManager; } 
注意,后台持续运行: (iOS8.0之前的方法)
CLLocationManagerDelegate 更新到位置之后调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 - (void )locationManager:(CLLocationManager  *)manager didUpdateLocations:(NSArray <CLLocation  *> *)locations {     NSLog (@"定位到了" );                    [manager stopUpdatingLocation];           } - (void )locationManager:(CLLocationManager  *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus )status {     switch  (status) {                      case  kCLAuthorizationStatusNotDetermined:         {             NSLog (@"用户还未决定" );             break ;         }                      case  kCLAuthorizationStatusRestricted:         {             NSLog (@"访问受限" );             break ;         }                      case  kCLAuthorizationStatusDenied:         {                          if ([CLLocationManager  locationServicesEnabled])             {                 NSLog (@"定位开启,但被拒" );             }else              {                 NSLog (@"定位关闭,不可用" );             }                          break ;         }                      case  kCLAuthorizationStatusAuthorizedAlways:                      {             NSLog (@"获取前后台定位授权" );             break ;         }                      case  kCLAuthorizationStatusAuthorizedWhenInUse:         {             NSLog (@"获得前台定位授权" );             break ;         }         default :             break ;     }      } - (void )locationManager:(CLLocationManager  *)manager didFailWithError:(NSError  *)error {     NSLog (@"更新失败" ); } 
获取到手机朝向时调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 - (CLLocationManager  *)locationManager {     if  (_locationManager == nil ) {                  _locationManager = [[CLLocationManager  alloc] init];         _locationManager.delegate = self ;                  _locationManager.headingFilter = 2 ;     }     return  _locationManager; } - (void )locationManager:(CLLocationManager  *)manager didUpdateHeading:(CLHeading  *)newHeading {     NSLog (@"%.2f" , newHeading.magneticHeading);               CGFloat  angle = newHeading.magneticHeading;          CGFloat  angleRadian = angle / 180.0  * M_PI;               [UIView  animateWithDuration:0.25  animations:^{         self .compassImageView.transform = CGAffineTransformMakeRotation (-angleRadian);     }];   } 
代理方法中有一个 CLHeading 的类,此类用法如下:
1 2 3 4 5 @property (readonly , nonatomic ) CLLocationDirection  magneticHeading;@property (readonly , nonatomic ) CLLocationDirection  trueHeading;
进入或离开区域时调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 - (void )locationManager:(CLLocationManager  *)manager didEnterRegion:(CLRegion  *)region {     NSLog (@"进入区域%@" , region.identifier); } - (void )locationManager:(CLLocationManager  *)manager didExitRegion:(CLRegion  *)region {     NSLog (@"离开区域%@" , region.identifier); } - (void )locationManager:(CLLocationManager  *)manager didDetermineState:(CLRegionState )state forRegion:(CLRegion  *)region {      } 
iOS8.0之后的适配 从 iOS8.0开始,苹果进一步加强了对用户隐私保护,当 APP 想访问用户的隐私信息时,系统不再自动弹出一个对话框让用户授权
解决方案:
一、调用 iOS8.0的 APL 主动请求用户授权
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 if  ([[UIDevice  currentDevice].systemVersion floatValue] >= 8.0 ) {                        [_locationManager requestAlwaysAuthorization];                         [_locationManager requestWhenInUseAuthorization]; } if  ([_locationManager respondsToSelector:@selector (requestAlwaysAuthorization)]) {                   [_locationManager requestAlwaysAuthorization];                         [_locationManager requestWhenInUseAuthorization]; } 
iOS9.0之后的适配 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19      [self .locationManager requestLocation]; 
CLLocation 详解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @property (readonly , nonatomic ) CLLocationCoordinate2D  coordinate;@property (readonly , nonatomic ) CLLocationDistance  altitude;@property (readonly , nonatomic ) CLLocationAccuracy  horizontalAccuracy;@property (readonly , nonatomic ) CLLocationAccuracy  verticalAccuracy;@property (readonly , nonatomic ) CLLocationDirection  course;@property (readonly , nonatomic ) CLLocationSpeed  speed;@property (readonly , nonatomic , copy ) NSDate  *timestamp;@property (readonly , nonatomic , copy , nullable ) CLFloor  *floor;@property  (nonatomic , readonly , copy ) NSString  *description;- (CLLocationDistance )getDistanceFrom:(const  CLLocation  *)location  - (CLLocationDistance )distanceFromLocation:(const  CLLocation  *)location 
示例一 做一个获取一个人的方向、移动多少米、并且打印
核心代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 CLLocation  *location = [locations lastObject];NSInteger  direction = location.course / 90 ;NSString  *directionStr = nil ;switch  (direction) {    case  0 :         directionStr = @"北偏东" ;         break ;     case  1 :         directionStr = @"东偏南" ;         break ;     case  2 :         directionStr = @"南偏西" ;         break ;     case  3 :         directionStr = @"西偏北" ;         break ;              default :         break ; } NSInteger  angle = (NSInteger )location.course % 90 ;directionStr = [NSString  stringWithFormat:@"%@%zd度" , directionStr, angle]; if  (angle == 0 ) {    NSRange  range = NSMakeRange (0 , 1 );     NSString  *subStr = [directionStr substringWithRange:range];     directionStr = [NSString  stringWithFormat:@"正%@" , subStr]; } double  distance = 0.0 ;if  (self .oldLocation != nil ) {    distance = [location distanceFromLocation:self .oldLocation]; } self .oldLocation = location;NSString  *locationStr = [NSString  stringWithFormat:@"%@方向,移动了%.2f米" , directionStr, distance];NSLog (@"%@" , locationStr);
示例二 指南针
1 2 3 4 5 6 7 8 9 10 11 NSLog (@"%.2f" , newHeading.magneticHeading);     CGFloat  angle = newHeading.magneticHeading;     CGFloat  angleRadian = angle / 180.0  * M_PI;     [UIView  animateWithDuration:0.25  animations:^{    self .compassImageView.transform = CGAffineTransformMakeRotation (-angleRadian); }]; 
区域监听 CLCircularRegion 1 2 3 4 5 6 7 CLLocationCoordinate2D  circleCenter = {21.13 , 123.456 };CLCircularRegion  *region = [[CLCircularRegion  alloc] initWithCenter:circleCenter radius:1000  identifier:@"lizhao" ];[self .locationManager startMonitoringForRegion:region];      [self .locationManager requestStateForRegion:region]; 
CLCircularRegion 1 2 3 4 - (instancetype )initWithCenter:(CLLocationCoordinate2D )center                             radius:(CLLocationDistance )radius                         identifier:(NSString  *)identifier; 
地理编码和反地理编码 地理编码需要接触到一个新的类 CLGeocoder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - (void )reverseGeocodeLocation:(CLLocation  *)location completionHandler:(CLGeocodeCompletionHandler )completionHandler; - (void )geocodeAddressDictionary:(NSDictionary  *)addressDictionary completionHandler:(CLGeocodeCompletionHandler )completionHandler; - (void )geocodeAddressString:(NSString  *)addressString completionHandler:(CLGeocodeCompletionHandler )completionHandler; - (void )geocodeAddressString:(NSString  *)addressString inRegion:(nullable  CLRegion  *)region completionHandler:(CLGeocodeCompletionHandler )completionHandler; - (void )cancelGeocode; 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [self .geoC geocodeAddressString:@"小码哥"  completionHandler:^(NSArray <CLPlacemark  *> * _Nullable placemarks, NSError  * _Nullable error) {          if (error == nil )     {         NSLog (@"%@" , placemarks);         [placemarks enumerateObjectsUsingBlock:^(CLPlacemark  * _Nonnull obj, NSUInteger  idx, BOOL  * _Nonnull stop) {             NSLog (@"%@" , obj.name);             self .addressTV.text = obj.name;             self .laTF.text = @(obj.location.coordinate.latitude).stringValue;             self .longTF.text = @(obj.location.coordinate.longitude).stringValue;         }];     }else      {         NSLog (@"cuowu--%@" , error.localizedDescription);     } }]; 
第三方框架 INTULocationManager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 [[INTULocationManager sharedInstance] requestLocationWithDesiredAccuracy:INTULocationAccuracyRoom timeout:10  block:^(CLLocation  *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {    if  (status == INTULocationStatusSuccess) {        NSLog (@"%@" , currentLocation);    }else     {        NSLog (@"定位失败" );    } }]; INTULocationRequestID requestID = [[INTULocationManager sharedInstance] requestLocationWithDesiredAccuracy:INTULocationAccuracyRoom timeout:10  delayUntilAuthorized:YES  block:^(CLLocation  *currentLocation, INTULocationAccuracy achievedAccuracy, INTULocationStatus status) {    if  (status == INTULocationStatusSuccess) {        NSLog (@"%@" , currentLocation);    }else     {        NSLog (@"定位失败" );    } }]; [[INTULocationManager sharedInstance] cancelLocationRequest:requestID];