1 //  ViewController.m
  2 //  CoreLocation框架的基本使用—定位
  3 // 注意 点:  1.设置地位可用 2. 设置允许本程序定位(对弹出的框,允许即可) 3. 为模拟器  设置位置移动方式, 比如 Freeway Drive(自由驾车模式)
  4 
  5 
  6 #import "ViewController.h"
  7 #import <CoreLocation/CoreLocation.h>
  8 
  9 #define isIOS(version) ([[UIDevice currentDevice].systemVersion floatValue] >= version)
 10 
 11 @interface ViewController ()<CLLocationManagerDelegate>
 12 {
 13     CLLocation *_lastLoc;
 14 }
 15 /** 位置管理者*/
 16 @property (nonatomic, strong) CLLocationManager *locM;
 17 
 18 @end
 19 
 20 @implementation ViewController
 21 
 22 #pragma mark - 懒加载
 23 /** locM属性的懒加载 */
 24 -(CLLocationManager *)locM
 25 {
 26     if (!_locM) {
 27             // 1. 创建位置管理者
 28         _locM = [[CLLocationManager alloc] init];
 29         // 1.1 block , 代理, 通知
 30         _locM.delegate = self;
 31         
 32         // 精确度越高, 越好点, 而且, 定位时间越长
 33         // 精确度
 34         _locM.desiredAccuracy = kCLLocationAccuracyBest;
 35         
 36         
 37         /** ----------iOS8.0+定位适配-------------- */
 38         
 39         //  如果两个授权请求,同时发送, 那么先执行第一个
 40         
 41         if(isIOS(8.0))
 42         {
 43             
 44             // 请求前后台定位授权
 45             // 无论是在前台还是后台, 都可以获取用户位置,而且不会出现蓝条
 46             // 无论是否勾选后台模式
 47             // 如果当前的授权状态 != 用户未选择状态, 那么这个方法不会有效
 48             // 如果当前授权状态 == 前台定位授权时, 这个方法也会有效
 49 //            [_locM requestAlwaysAuthorization];
 50             
 51             
 52             // 请求前台定位授权
 53             // 在前台授权下, 默认只能在前台获取用户位置信息, 如果想要在后台获取用户位置, 那么 勾选后台模式 Location updates (会出现蓝条)
 54              // 如果当前的授权状态 != 用户未选择状态, 那么这个方法不会有效
 55             [_locM requestWhenInUseAuthorization];
 56             
 57             
 58             // 在前台授权下, 默认只能在前台获取用户位置信息, 如果想要在后台获取用户位置, 那么 勾选后台模式 Location updates (会出现蓝条), 需要额外的设置一下属性为YES
 59             if (isIOS(9.0)) {
 60 //                _locM.allowsBackgroundLocationUpdates = YES;
 61             }
 62             
 63 
 64         }
 65         
 66         
 67     }
 68     return _locM;
 69 }
 70 
 71 
 72 
 73 
 74 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
 75 {
 76 
 77     // 2. 开始更新用户位置
 78     // start 开始某个服务  stop 停止某个服务
 79     // 一旦我们调用了这个方法, 那么就会在后台不断的获取用户位置, 然后告诉外界
 80     // 标准化定位(gps/ 基站 / WiFi)
 81     //
 82     [self.locM startUpdatingLocation];
 83     
 84     
 85     // 显著位置变化(基站)(要求设备必须由电话模块)
 86     // 当app 被杀死时也可以接收到位置通知(app -- 后台  )
 87 //    [self.locM startMonitoringSignificantLocationChanges];
 88     
 89     
 90     /**
 91      *   ———————————应用场景—————————————
 92      1) 如果要求定位及时,精度较高,并且运行时间较短,可使用标准定位;
 93      2) 如果长时间监控用户位置,用户移动速度比较快(例如打车软件),可使用后者
 94      *
 95      */
 96     
 97     /**
 98      *  extern const CLLocationAccuracy kCLLocationAccuracyBest;
 99      extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;
100      extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;
101      extern const CLLocationAccuracy kCLLocationAccuracyKilometer;
102      extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;ß
103      */
104     
105 //    [self.locM requestLocation];
106     
107     
108     
109 }
110 
111 
112 #pragma mark - CLLocationManagerDelegate
113 
114 /**
115  *  获取到位置信息时调用
116  *
117  *  @param manager   位置管理者
118  *  @param locations 位置数组
119  */
120 -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
121 {
122 //    NSLog(@"获取到位置");
123     
124     CLLocation *loc = [locations lastObject];
125     
126     
127     NSLog(@"%lf",loc.horizontalAccuracy);
128     // 代表当前位置  horizontalAccuracy>0 才是有效的
129     if(loc.horizontalAccuracy > 0)
130     {
131         
132     /**
133      *  CLLocation
134      * coordinate : 经纬度
135       altitude :海拔
136      course : 航向
137       speed : 速度
138      distanceFromLocation : 计算两个点之间的直线物理距离
139      */
140     
141     /**
142      *  场景演示:打印当前用户的行走方向,偏离角度以及对应的行走距离,
143      例如:”北偏东 30度  方向,移动了 8米  ”
144      */
145     
146     // 确定航向
147     NSString *angleStr = nil;
148     switch ((int)loc.course / 90) {
149         case 0:
150             angleStr = @"北偏东";
151             break;
152         case 1:
153             angleStr = @"东偏南";
154             break;
155         case 2:
156             angleStr = @"南偏西";
157             break;
158         case 3:
159             angleStr = @"西偏北";
160             break;
161             
162         default:
163             angleStr = @"掉沟里去了";
164             break;
165     }
166     
167     // 确定偏离角度
168     int angle = 0;
169     angle = (int)loc.course % 90;
170     // 正方向
171     if (angle == 0) {
172         angleStr = [angleStr substringToIndex:1];
173     }
174     
175     
176     // 移动了多少
177     CLLocationDistance distance = 0;
178     if (_lastLoc) {
179         distance = [loc distanceFromLocation:_lastLoc];
180     }
181     _lastLoc = loc;
182     
183     // 拼串
184     // 例如:”北偏东 30度  方向,移动了 8米  ”
185     
186     NSString *str ;
187     if (angle == 0) {
188         str = [NSString stringWithFormat:@"正%@方向, 移动了%f米", angleStr, distance];
189     }else
190     {
191         str = [NSString stringWithFormat:@"%@%zd度方向, 移动了%f米", angleStr , angle, distance];
192     }
193     
194     
195     
196     NSLog(@"%@", str);
197     
198     }
199     
200     // 如果我们想要定位一次
201     
202     // 停止位置更新
203 //    [manager stopUpdatingLocation];
204 }
205 
206 /**
207  *  当前授权状态发生变化时调用
208  *
209  *  @param manager 位置管理者
210  *  @param status  状态
211  */
212 -(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
213 {
214     switch (status) {
215         case kCLAuthorizationStatusNotDetermined:
216         {
217             NSLog(@"用户未选择");
218             break;
219         }
220         case kCLAuthorizationStatusRestricted:
221         {
222             NSLog(@"受限制");
223             break;
224         }
225         case kCLAuthorizationStatusDenied:
226         {
227 
228             // 确定当前设备, 是否支持定位,或者定位服务是否开启
229             if([CLLocationManager locationServicesEnabled])
230             {
231                 NSLog(@"拒绝");
232                 
233                 // 我们可以调用代码, 打开设置界面
234                 NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
235                 if ([[UIApplication sharedApplication] canOpenURL:url]) {
236                     [[UIApplication sharedApplication] openURL:url];
237                 }
238                 
239                 
240             }else
241             {
242                 NSLog(@"服务关闭");
243             }
244             
245             break;
246         }
247         case kCLAuthorizationStatusAuthorizedAlways:
248         {
249             NSLog(@"前后台定位授权");
250             break;
251         }
252         case kCLAuthorizationStatusAuthorizedWhenInUse:
253         {
254             NSLog(@"前台定位授权");
255             break;
256         }
257             
258             
259         default:
260             break;
261     }
262 }
263 
264 /**
265  *  定位失败
266  *
267  *  @param manager 位置管理者
268  *  @param error   错误
269  */
270 -(void)locationManager:(nonnull CLLocationManager *)manager didFailWithError:(nonnull NSError *)error
271 {
272     NSLog(@"fail%@",error);
273 
274 }
275 
276 @end