精通iOS开发--第19章 Core Location 和 Map Kit 01 Capabilities 下 示例程序
2016-07-09 21:58
357 查看
第19章 Core Location
和 Map Kit 01 Capabilities
下
CLLocation+Description.h
//
// CLLocation+Description.h
// CLLocationManagerTest
//
// Created by ranzhou on 16/7/8.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import <CoreLocation/CoreLocation.h>
@interface CLLocation (Description)
- (void)descripeCLLocation:(CLLocation*)location;
@end
CLLocation+Description.m
//
// CLLocation+Description.m
// CLLocationManagerTest
//
// Created by ranzhou on 16/7/8.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import "CLLocation+Description.h"
// Core Location
@implementation CLLocation (Description)
- (void)descripeCLLocation:(CLLocation*)location {
// 地理坐标 // coordinate |kəʊˈɔːdɪnət| noun
坐标
CLLocationCoordinate2D coordinate = location.coordinate;
// 纬度 // latitude |ˈlætɪtjuːd| noun
纬度
NSLog(@"%f",coordinate.latitude);
// 经度 // longitude |ˈlɒndʒɪtjuːd| noun
经度
NSLog(@"%f",coordinate.longitude);
/*
水平精度,horizontalAccuracy描述了以coordinate为圆心的圆的半径,horizontalAccuracy越小精度越高。
若horizontalAccuracy为负值,则表示由于某种原因,而导致无法信任coordinate的值。
horizontal |ˌhɒrɪˈzɒntl| adjective 水平的。
accuracy |ˈækjərəsi| noun Uncountable 精确。
*/
NSLog(@"%f",location.horizontalAccuracy);
// 海拔高度 // altitude |ˈæltɪtjuːd, American -tuːd| noun
海拔
NSLog(@"%f",location.altitude);
// 垂直精度,表示海拔高度的精度,如果值为负的,则表示无法获取有效海拔高度。
NSLog(@"%f",location.verticalAccuracy);
// 时间戳,描述的是位置管理器确定位置的时间。
NSLog(@"%@",[location.timestamp
dateByAddingTimeInterval:[[NSTimeZone
localTimeZone]secondsFromGMT]]);
}
@end
BIDPlace.h
//
// BIDPlace.h
// CLLocationManagerTest
//
// Created by ranzhou on 16/7/7.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
// Map Kit annotation |ˌænəˈteɪʃn| noun 注释
@interface BIDPlace :
NSObject<MKAnnotation>
@property (copy,nonatomic)
NSString *title;
// subtitle |ˈsʌbtaɪtl| noun 副标题
@property (copy,nonatomic)
NSString *subtitle;
@property (nonatomic,assign)
CLLocationCoordinate2D coordinate;
@property (nonatomic,strong)
CLLocation* location;
@end
BIDPlace.m
//
// BIDPlace.m
// CLLocationManagerTest
//
// Created by ranzhou on 16/7/7.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import "BIDPlace.h"
@implementation BIDPlace
@end
ViewController.m
//
// ViewController.m
// CLLocationManagerTest
//
// Created by ranzhou on 16/7/7.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import "ViewController.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "BIDPlace.h"
#define TempDescript ([NSString stringWithFormat:@"Class:%@ Cmd:%@ Line:%i",[self class],NSStringFromSelector(_cmd),__LINE__])
@interface
ViewController () <CLLocationManagerDelegate,MKMapViewDelegate>
@property (nonatomic,strong)
CLLocationManager *locationManager;
@property (nonatomic,strong)
MKMapView *mapView;
@property (nonatomic,strong)
NSMutableArray<BIDPlace *> *BIDPlaceArry;
@property (nonatomic,assign)
double totalDistance;
// -------------------------------------------------------------------
@property (nonatomic,assign)
CLLocationCoordinate2D firstUserLocation;
@property (nonatomic,assign)
CLLocationCoordinate2D firstLocationResult;
// -------------------------------------------------------------------
@property (nonatomic,strong)
NSMutableString *reportStr;
@end
@implementation ViewController
- (void)loadTheMapView
{
self.mapView = [[MKMapView
alloc]initWithFrame:self.view.bounds];
// 自动显示用户的位置,Set to YES to add the user location annotation to the map and start updating its location,因为我们获取到的地理位置与真实位置有偏差,所以通过这个方法来取得正确的促初始位置。
self.mapView.showsUserLocation
= YES;
self.mapView.delegate =
self;
self.mapView.translatesAutoresizingMaskIntoConstraints
= NO;
[self.view
addSubview:self.mapView];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:self.view
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.mapView
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0.0]];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:self.view
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.mapView
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0.0]];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:self.view
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.mapView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:self.view
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.mapView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]];
}
- (void)beginUpdatingLocation
{
if ([CLLocationManager
locationServicesEnabled])
{
self.locationManager = [[CLLocationManager
alloc] init];
/*
在iOS 8.0下要授权,iOS8以后采用了新的授权方式,需要再Info.plist中注册提示的内容。
*/
if ([[[UIDevice
currentDevice] systemVersion]
floatValue] >= 8.0)
{
// NSLocationAlwaysUsageDescription
[self.locationManager
requestAlwaysAuthorization];
// NSLocationWhenInUseUsageDescription // authorization |ˌɔːθəraɪˈzeɪʃn| noun
授权、批准
//[self.locationManager requestWhenInUseAuthorization];
}
}
self.locationManager.delegate
= self;
// desiredAccuracy是一个double类型,代表m,kCLLocationAccuracyBest表示提供最好的精度。
// desire |dɪˈzaɪə(r)| noun、v
渴望
self.locationManager.desiredAccuracy
= kCLLocationAccuracyBest;
// 默认情况下,位置管理器会把检测到的位置更改通知给委托。制定距离筛选器意味着告知位置管理器不要将更改都通知你,仅当位置更改超过特定大小时通知你。设置距离筛选器可以减少应用执行的轮询数量。代表m。
// filter |ˈfɪltə(r)| n
过滤器
self.locationManager.distanceFilter
= 20;
// 设置成kCLDistanceFilterNone后将取消前面的distanceFilter相关的设置。恢复到没有筛选器的状态。
// self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.activityType
= CLActivityTypeFitness;
self.locationManager.allowsBackgroundLocationUpdates
= YES;
self.locationManager.pausesLocationUpdatesAutomatically
= NO;
// 启动位置管理器。
[self.locationManager
startUpdatingLocation];
}
- (void)viewDidLoad
{
[super
viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.reportStr = [[NSMutableString
alloc]init];
[[NSFileManager
defaultManager]removeItemAtPath:[self
createFileName]
error:NULL];
self.totalDistance =
0;
self.BIDPlaceArry = [[NSMutableArray
alloc]init];
BIDPlace *bid = [[BIDPlace
alloc]init];
bid.title =
@"起始位置";
bid.subtitle =
@"起始位置";
[self.BIDPlaceArry
addObject:bid];
[self
loadTheMapView];
[self
beginUpdatingLocation];
[self
loadButton];
BOOL bb = [CLLocationManager
significantLocationChangeMonitoringAvailable];
NSLog(@"%i",bb);
NSLog(@"%i",[UIDevice
currentDevice].multitaskingSupported);
}
-(void)loadButton {
UIButton *tempButton = [[UIButton
alloc]init];
tempButton.backgroundColor = [[UIColor
lightGrayColor]colorWithAlphaComponent:0.5];
[self.view
addSubview:tempButton];
[tempButton addTarget:self
action:@selector(showReport)
forControlEvents:UIControlEventTouchUpInside];
tempButton.translatesAutoresizingMaskIntoConstraints =
NO;
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:tempButton
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:NULL
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:200]];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:tempButton
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:NULL
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:40]];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:tempButton
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0]];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:self.view
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:tempButton
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:20]];
}
- (void)showReport
{
//NSString *str = [NSString stringWithContentsOfFile:[self createFileName] encoding:NSUTF8StringEncoding error:NULL];
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:@"日志"
message:self.reportStr
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction
actionWithTitle:@"取消"
style:UIAlertActionStyleCancel
handler:nil];
UIAlertAction *okAction = [UIAlertAction
actionWithTitle:@"好的"
style:UIAlertActionStyleDefault
handler:nil];
[alertController addAction:cancelAction];
[alertController addAction:okAction];
[self
presentViewController:alertController
animated:YES
completion:nil];
}
/*
1:对于国内地图而言,使用LocationManager定位所获得经纬度,是有一段较大距离的偏移的,国内地图使用的坐标系统是GCJ-02而ios
sdk中所用到的是国际标准的坐标系统WGS-84。因为国内使用的是加密后的坐标系GCJ-02就是网络上叫的火星坐标。
2:locationManager就是因为得到的是火星坐标偏移后的经纬度,所以导致在MapView上有很大的偏差,而在MKMapView上通过定位自己位置所获得的经纬度有是准确,因为apple已经对国内地图做了偏移优化。
3:那么临时的解决方法:想要获得自己准确的经纬度可以直接通过MKMapView中对自身定位来获得:
*/
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation
*)userLocation
{
static
dispatch_once_t once;
dispatch_once(&once, ^{
dispatch_async(dispatch_get_main_queue(), ^{
self.firstUserLocation = userLocation.coordinate;
// 他告诉地图要显示地图的哪一部分
MKCoordinateRegion coordinateRegion =
MKCoordinateRegionMakeWithDistance(userLocation.location.coordinate,
1000, 1000);
[self.mapView
setRegion:coordinateRegion
animated:YES];
self.BIDPlaceArry.firstObject.coordinate
= userLocation.location.coordinate;
[self.mapView
addAnnotation:self.BIDPlaceArry.firstObject];
});
});
}
// 无法确定位置时回调的方法。测试发现经常会出现kCLErrorLocationUnknown错误,随后打开原生地图后再打开就没有问题了。然后过一会又会报kCLErrorLocationUnknown错误。关闭屏幕后重新打开,又会恢复。这应该不是一个错误,因该是苹果为了省电自动做的处理。参考:self.locationManager.activityType
= CLActivityTypeFitness;
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError
*)error
{
if (error.code ==
kCLErrorLocationUnknown)
{
NSLog(@"kCLErrorLocationUnknown");
}
else
if(error.code ==
kCLErrorDenied)
{
// deny |dɪˈnaɪ| v
否认
NSLog(@"kCLErrorDenied");
}
else
{
NSLog(@"Error.code:%li",error.code);
}
}
// overlay |ˌəʊvəˈleɪ|transitive verb 覆盖 |ˈəʊvəleɪ|noun
覆盖物
// polyline ['pɒli:laɪn] n 折线
// render |ˈrendə(r)| v 描述、给某某抹灰
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id
<MKOverlay>)overlay
{
if ([overlay
isKindOfClass:[MKPolyline
class]])
{
MKPolylineRenderer *renderer=[[MKPolylineRenderer
alloc]initWithOverlay:overlay];
// stroke |strəʊk|
renderer.strokeColor=[[UIColor
redColor]colorWithAlphaComponent:0.5];
renderer.lineWidth=2.0;
return renderer;
}
if([overlay
isKindOfClass:[MKCircle
class]])
{
MKCircleRenderer *circle = [[MKCircleRenderer
alloc]initWithOverlay:overlay];
circle.lineWidth =
2.0;
circle.strokeColor = [UIColor
blueColor];
circle.fillColor = [[UIColor
blueColor]colorWithAlphaComponent:0.5];
return circle;
}
if([overlay
isKindOfClass:[MKPolygon
class]])
{
MKPolygonRenderer *polygon = [[MKPolygonRenderer
alloc]initWithOverlay:overlay];
polygon.lineWidth =
2.0;
polygon.strokeColor = [UIColor
yellowColor];
polygon.fillColor = [[UIColor
yellowColor]colorWithAlphaComponent:0.5];
return polygon;
}
return
nil;
}
/*
manager:第一个参数是该方法的位置管理器。
locations:第二个参数代表的是位置数组,有可能多次位置更新一次性上报,无论何时,数组的最后一项都表示当前位置。
*/
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation
*> *)locations {
CLLocation *lastLocation = locations.lastObject;
// 如果精度太低则放弃次操作。
if (lastLocation.horizontalAccuracy >
66.0 || lastLocation.horizontalAccuracy<0)
{
return;
}
// 在下面的代码中记录第一次获取到的经纬度。
static
dispatch_once_t once;
dispatch_once(&once, ^{
self.firstLocationResult = lastLocation.coordinate;
// 记录location是为了计算讲个location之间的距离使用。
self.BIDPlaceArry.firstObject.location
= lastLocation;
});
// 如果此时UserLocation还某有更新则return,等待其获取到数据后才继续操作。
if (self.firstUserLocation.longitude==0
|| self.firstUserLocation.latitude==0)
{
return;
}
NSMutableArray<CLLocation*> *locationArry = [[NSMutableArray
alloc]init];
[locationArry addObject:[self.BIDPlaceArry
lastObject].location];
for(int i=0; i<locations.count;
i++)
{
CLLocation *location = [locations
objectAtIndex:i];
if (location.horizontalAccuracy >
70 || location.horizontalAccuracy<0)
{
continue;
}
// 如果新获取到的地理位置只移动了很小的距离,则不记录。
double newDistance = newDistance = [locationArry.lastObject
distanceFromLocation:location];
if (newDistance <
30)
{
continue;
}
[locationArry addObject:location];
}
// 声明一个数组
用来存放画线的点。
CLLocationCoordinate2D coords[locationArry.count];
coords[0] = [self
justTheCLLocationCoordinate2D:locationArry.firstObject.coordinate];
for (int i=1; i<locationArry.count;
i++)
{
CLLocation *tempLocation = [locationArry
objectAtIndex:i];
coords[i] = [self
justTheCLLocationCoordinate2D:tempLocation.coordinate];
BIDPlace *newBID = [[BIDPlace
alloc]init];
newBID.title = [NSString
stringWithFormat:@"%lu",(unsigned
long)self.BIDPlaceArry.count];
newBID.coordinate = coords[i];
newBID.location = tempLocation;
double newDistance = [[locationArry
objectAtIndex:i-1]
distanceFromLocation:tempLocation];
self.totalDistance += newDistance;
newBID.subtitle = [NSString
stringWithFormat:@"行程:%f",self.totalDistance];
[self.BIDPlaceArry
addObject:newBID];
// 添加新的标记点。
[self.mapView
addAnnotation:newBID];
}
// 在不改变缩放级别的情况下,移动到当前位置。
// centerCoordinate allows the coordinate of the region to be changed without changing the zoom level.
[self.mapView
setCenterCoordinate:coords[locationArry.count-1]
animated:YES];
// 在地图上画线
MKPolyline *polyline = [MKPolyline
polylineWithCoordinates:coords
count:locationArry.count];
[self.mapView
addOverlay:polyline
level:MKOverlayLevelAboveLabels];
}
- (CLLocationCoordinate2D)justTheCLLocationCoordinate2D:(CLLocationCoordinate2D)coor
{
CLLocationCoordinate2D coord = coor;
coord.longitude = coord.longitude -( self.firstLocationResult.longitude-self.firstUserLocation.longitude);
coord.latitude = coord.latitude - (self.firstLocationResult.latitude -
self.firstUserLocation.latitude);
return coord;
}
- (void)reportRecode:(NSString *)str
{
static NSString *path;
if (path==NULL) {
path = [self createFileName];
}
[[NSString stringWithFormat:@"%@\n",str] writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}
- (NSString*)createFileName
{
NSArray *paths =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *documentsDirectory = [paths
objectAtIndex:0];
NSString *filePath = [documentsDirectory
stringByAppendingPathComponent:[NSString
stringWithFormat:@"%@.txt",@"调试日志"]];
return filePath;
}
@end
和 Map Kit 01 Capabilities
下
CLLocation+Description.h
//
// CLLocation+Description.h
// CLLocationManagerTest
//
// Created by ranzhou on 16/7/8.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import <CoreLocation/CoreLocation.h>
@interface CLLocation (Description)
- (void)descripeCLLocation:(CLLocation*)location;
@end
CLLocation+Description.m
//
// CLLocation+Description.m
// CLLocationManagerTest
//
// Created by ranzhou on 16/7/8.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import "CLLocation+Description.h"
// Core Location
@implementation CLLocation (Description)
- (void)descripeCLLocation:(CLLocation*)location {
// 地理坐标 // coordinate |kəʊˈɔːdɪnət| noun
坐标
CLLocationCoordinate2D coordinate = location.coordinate;
// 纬度 // latitude |ˈlætɪtjuːd| noun
纬度
NSLog(@"%f",coordinate.latitude);
// 经度 // longitude |ˈlɒndʒɪtjuːd| noun
经度
NSLog(@"%f",coordinate.longitude);
/*
水平精度,horizontalAccuracy描述了以coordinate为圆心的圆的半径,horizontalAccuracy越小精度越高。
若horizontalAccuracy为负值,则表示由于某种原因,而导致无法信任coordinate的值。
horizontal |ˌhɒrɪˈzɒntl| adjective 水平的。
accuracy |ˈækjərəsi| noun Uncountable 精确。
*/
NSLog(@"%f",location.horizontalAccuracy);
// 海拔高度 // altitude |ˈæltɪtjuːd, American -tuːd| noun
海拔
NSLog(@"%f",location.altitude);
// 垂直精度,表示海拔高度的精度,如果值为负的,则表示无法获取有效海拔高度。
NSLog(@"%f",location.verticalAccuracy);
// 时间戳,描述的是位置管理器确定位置的时间。
NSLog(@"%@",[location.timestamp
dateByAddingTimeInterval:[[NSTimeZone
localTimeZone]secondsFromGMT]]);
}
@end
BIDPlace.h
//
// BIDPlace.h
// CLLocationManagerTest
//
// Created by ranzhou on 16/7/7.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
// Map Kit annotation |ˌænəˈteɪʃn| noun 注释
@interface BIDPlace :
NSObject<MKAnnotation>
@property (copy,nonatomic)
NSString *title;
// subtitle |ˈsʌbtaɪtl| noun 副标题
@property (copy,nonatomic)
NSString *subtitle;
@property (nonatomic,assign)
CLLocationCoordinate2D coordinate;
@property (nonatomic,strong)
CLLocation* location;
@end
BIDPlace.m
//
// BIDPlace.m
// CLLocationManagerTest
//
// Created by ranzhou on 16/7/7.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import "BIDPlace.h"
@implementation BIDPlace
@end
ViewController.m
//
// ViewController.m
// CLLocationManagerTest
//
// Created by ranzhou on 16/7/7.
// Copyright © 2016年 ranzhouee. All rights reserved.
//
#import "ViewController.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "BIDPlace.h"
#define TempDescript ([NSString stringWithFormat:@"Class:%@ Cmd:%@ Line:%i",[self class],NSStringFromSelector(_cmd),__LINE__])
@interface
ViewController () <CLLocationManagerDelegate,MKMapViewDelegate>
@property (nonatomic,strong)
CLLocationManager *locationManager;
@property (nonatomic,strong)
MKMapView *mapView;
@property (nonatomic,strong)
NSMutableArray<BIDPlace *> *BIDPlaceArry;
@property (nonatomic,assign)
double totalDistance;
// -------------------------------------------------------------------
@property (nonatomic,assign)
CLLocationCoordinate2D firstUserLocation;
@property (nonatomic,assign)
CLLocationCoordinate2D firstLocationResult;
// -------------------------------------------------------------------
@property (nonatomic,strong)
NSMutableString *reportStr;
@end
@implementation ViewController
- (void)loadTheMapView
{
self.mapView = [[MKMapView
alloc]initWithFrame:self.view.bounds];
// 自动显示用户的位置,Set to YES to add the user location annotation to the map and start updating its location,因为我们获取到的地理位置与真实位置有偏差,所以通过这个方法来取得正确的促初始位置。
self.mapView.showsUserLocation
= YES;
self.mapView.delegate =
self;
self.mapView.translatesAutoresizingMaskIntoConstraints
= NO;
[self.view
addSubview:self.mapView];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:self.view
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.mapView
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0.0]];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:self.view
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.mapView
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0.0]];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:self.view
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.mapView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:self.view
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.mapView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]];
}
- (void)beginUpdatingLocation
{
if ([CLLocationManager
locationServicesEnabled])
{
self.locationManager = [[CLLocationManager
alloc] init];
/*
在iOS 8.0下要授权,iOS8以后采用了新的授权方式,需要再Info.plist中注册提示的内容。
*/
if ([[[UIDevice
currentDevice] systemVersion]
floatValue] >= 8.0)
{
// NSLocationAlwaysUsageDescription
[self.locationManager
requestAlwaysAuthorization];
// NSLocationWhenInUseUsageDescription // authorization |ˌɔːθəraɪˈzeɪʃn| noun
授权、批准
//[self.locationManager requestWhenInUseAuthorization];
}
}
self.locationManager.delegate
= self;
// desiredAccuracy是一个double类型,代表m,kCLLocationAccuracyBest表示提供最好的精度。
// desire |dɪˈzaɪə(r)| noun、v
渴望
self.locationManager.desiredAccuracy
= kCLLocationAccuracyBest;
// 默认情况下,位置管理器会把检测到的位置更改通知给委托。制定距离筛选器意味着告知位置管理器不要将更改都通知你,仅当位置更改超过特定大小时通知你。设置距离筛选器可以减少应用执行的轮询数量。代表m。
// filter |ˈfɪltə(r)| n
过滤器
self.locationManager.distanceFilter
= 20;
// 设置成kCLDistanceFilterNone后将取消前面的distanceFilter相关的设置。恢复到没有筛选器的状态。
// self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.activityType
= CLActivityTypeFitness;
self.locationManager.allowsBackgroundLocationUpdates
= YES;
self.locationManager.pausesLocationUpdatesAutomatically
= NO;
// 启动位置管理器。
[self.locationManager
startUpdatingLocation];
}
- (void)viewDidLoad
{
[super
viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.reportStr = [[NSMutableString
alloc]init];
[[NSFileManager
defaultManager]removeItemAtPath:[self
createFileName]
error:NULL];
self.totalDistance =
0;
self.BIDPlaceArry = [[NSMutableArray
alloc]init];
BIDPlace *bid = [[BIDPlace
alloc]init];
bid.title =
@"起始位置";
bid.subtitle =
@"起始位置";
[self.BIDPlaceArry
addObject:bid];
[self
loadTheMapView];
[self
beginUpdatingLocation];
[self
loadButton];
BOOL bb = [CLLocationManager
significantLocationChangeMonitoringAvailable];
NSLog(@"%i",bb);
NSLog(@"%i",[UIDevice
currentDevice].multitaskingSupported);
}
-(void)loadButton {
UIButton *tempButton = [[UIButton
alloc]init];
tempButton.backgroundColor = [[UIColor
lightGrayColor]colorWithAlphaComponent:0.5];
[self.view
addSubview:tempButton];
[tempButton addTarget:self
action:@selector(showReport)
forControlEvents:UIControlEventTouchUpInside];
tempButton.translatesAutoresizingMaskIntoConstraints =
NO;
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:tempButton
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:NULL
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:200]];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:tempButton
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:NULL
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:40]];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:tempButton
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0]];
[self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:self.view
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:tempButton
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:20]];
}
- (void)showReport
{
//NSString *str = [NSString stringWithContentsOfFile:[self createFileName] encoding:NSUTF8StringEncoding error:NULL];
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:@"日志"
message:self.reportStr
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction
actionWithTitle:@"取消"
style:UIAlertActionStyleCancel
handler:nil];
UIAlertAction *okAction = [UIAlertAction
actionWithTitle:@"好的"
style:UIAlertActionStyleDefault
handler:nil];
[alertController addAction:cancelAction];
[alertController addAction:okAction];
[self
presentViewController:alertController
animated:YES
completion:nil];
}
/*
1:对于国内地图而言,使用LocationManager定位所获得经纬度,是有一段较大距离的偏移的,国内地图使用的坐标系统是GCJ-02而ios
sdk中所用到的是国际标准的坐标系统WGS-84。因为国内使用的是加密后的坐标系GCJ-02就是网络上叫的火星坐标。
2:locationManager就是因为得到的是火星坐标偏移后的经纬度,所以导致在MapView上有很大的偏差,而在MKMapView上通过定位自己位置所获得的经纬度有是准确,因为apple已经对国内地图做了偏移优化。
3:那么临时的解决方法:想要获得自己准确的经纬度可以直接通过MKMapView中对自身定位来获得:
*/
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation
*)userLocation
{
static
dispatch_once_t once;
dispatch_once(&once, ^{
dispatch_async(dispatch_get_main_queue(), ^{
self.firstUserLocation = userLocation.coordinate;
// 他告诉地图要显示地图的哪一部分
MKCoordinateRegion coordinateRegion =
MKCoordinateRegionMakeWithDistance(userLocation.location.coordinate,
1000, 1000);
[self.mapView
setRegion:coordinateRegion
animated:YES];
self.BIDPlaceArry.firstObject.coordinate
= userLocation.location.coordinate;
[self.mapView
addAnnotation:self.BIDPlaceArry.firstObject];
});
});
}
// 无法确定位置时回调的方法。测试发现经常会出现kCLErrorLocationUnknown错误,随后打开原生地图后再打开就没有问题了。然后过一会又会报kCLErrorLocationUnknown错误。关闭屏幕后重新打开,又会恢复。这应该不是一个错误,因该是苹果为了省电自动做的处理。参考:self.locationManager.activityType
= CLActivityTypeFitness;
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError
*)error
{
if (error.code ==
kCLErrorLocationUnknown)
{
NSLog(@"kCLErrorLocationUnknown");
}
else
if(error.code ==
kCLErrorDenied)
{
// deny |dɪˈnaɪ| v
否认
NSLog(@"kCLErrorDenied");
}
else
{
NSLog(@"Error.code:%li",error.code);
}
}
// overlay |ˌəʊvəˈleɪ|transitive verb 覆盖 |ˈəʊvəleɪ|noun
覆盖物
// polyline ['pɒli:laɪn] n 折线
// render |ˈrendə(r)| v 描述、给某某抹灰
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id
<MKOverlay>)overlay
{
if ([overlay
isKindOfClass:[MKPolyline
class]])
{
MKPolylineRenderer *renderer=[[MKPolylineRenderer
alloc]initWithOverlay:overlay];
// stroke |strəʊk|
renderer.strokeColor=[[UIColor
redColor]colorWithAlphaComponent:0.5];
renderer.lineWidth=2.0;
return renderer;
}
if([overlay
isKindOfClass:[MKCircle
class]])
{
MKCircleRenderer *circle = [[MKCircleRenderer
alloc]initWithOverlay:overlay];
circle.lineWidth =
2.0;
circle.strokeColor = [UIColor
blueColor];
circle.fillColor = [[UIColor
blueColor]colorWithAlphaComponent:0.5];
return circle;
}
if([overlay
isKindOfClass:[MKPolygon
class]])
{
MKPolygonRenderer *polygon = [[MKPolygonRenderer
alloc]initWithOverlay:overlay];
polygon.lineWidth =
2.0;
polygon.strokeColor = [UIColor
yellowColor];
polygon.fillColor = [[UIColor
yellowColor]colorWithAlphaComponent:0.5];
return polygon;
}
return
nil;
}
/*
manager:第一个参数是该方法的位置管理器。
locations:第二个参数代表的是位置数组,有可能多次位置更新一次性上报,无论何时,数组的最后一项都表示当前位置。
*/
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation
*> *)locations {
CLLocation *lastLocation = locations.lastObject;
// 如果精度太低则放弃次操作。
if (lastLocation.horizontalAccuracy >
66.0 || lastLocation.horizontalAccuracy<0)
{
return;
}
// 在下面的代码中记录第一次获取到的经纬度。
static
dispatch_once_t once;
dispatch_once(&once, ^{
self.firstLocationResult = lastLocation.coordinate;
// 记录location是为了计算讲个location之间的距离使用。
self.BIDPlaceArry.firstObject.location
= lastLocation;
});
// 如果此时UserLocation还某有更新则return,等待其获取到数据后才继续操作。
if (self.firstUserLocation.longitude==0
|| self.firstUserLocation.latitude==0)
{
return;
}
NSMutableArray<CLLocation*> *locationArry = [[NSMutableArray
alloc]init];
[locationArry addObject:[self.BIDPlaceArry
lastObject].location];
for(int i=0; i<locations.count;
i++)
{
CLLocation *location = [locations
objectAtIndex:i];
if (location.horizontalAccuracy >
70 || location.horizontalAccuracy<0)
{
continue;
}
// 如果新获取到的地理位置只移动了很小的距离,则不记录。
double newDistance = newDistance = [locationArry.lastObject
distanceFromLocation:location];
if (newDistance <
30)
{
continue;
}
[locationArry addObject:location];
}
// 声明一个数组
用来存放画线的点。
CLLocationCoordinate2D coords[locationArry.count];
coords[0] = [self
justTheCLLocationCoordinate2D:locationArry.firstObject.coordinate];
for (int i=1; i<locationArry.count;
i++)
{
CLLocation *tempLocation = [locationArry
objectAtIndex:i];
coords[i] = [self
justTheCLLocationCoordinate2D:tempLocation.coordinate];
BIDPlace *newBID = [[BIDPlace
alloc]init];
newBID.title = [NSString
stringWithFormat:@"%lu",(unsigned
long)self.BIDPlaceArry.count];
newBID.coordinate = coords[i];
newBID.location = tempLocation;
double newDistance = [[locationArry
objectAtIndex:i-1]
distanceFromLocation:tempLocation];
self.totalDistance += newDistance;
newBID.subtitle = [NSString
stringWithFormat:@"行程:%f",self.totalDistance];
[self.BIDPlaceArry
addObject:newBID];
// 添加新的标记点。
[self.mapView
addAnnotation:newBID];
}
// 在不改变缩放级别的情况下,移动到当前位置。
// centerCoordinate allows the coordinate of the region to be changed without changing the zoom level.
[self.mapView
setCenterCoordinate:coords[locationArry.count-1]
animated:YES];
// 在地图上画线
MKPolyline *polyline = [MKPolyline
polylineWithCoordinates:coords
count:locationArry.count];
[self.mapView
addOverlay:polyline
level:MKOverlayLevelAboveLabels];
}
- (CLLocationCoordinate2D)justTheCLLocationCoordinate2D:(CLLocationCoordinate2D)coor
{
CLLocationCoordinate2D coord = coor;
coord.longitude = coord.longitude -( self.firstLocationResult.longitude-self.firstUserLocation.longitude);
coord.latitude = coord.latitude - (self.firstLocationResult.latitude -
self.firstUserLocation.latitude);
return coord;
}
- (void)reportRecode:(NSString *)str
{
static NSString *path;
if (path==NULL) {
path = [self createFileName];
}
[[NSString stringWithFormat:@"%@\n",str] writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}
- (NSString*)createFileName
{
NSArray *paths =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *documentsDirectory = [paths
objectAtIndex:0];
NSString *filePath = [documentsDirectory
stringByAppendingPathComponent:[NSString
stringWithFormat:@"%@.txt",@"调试日志"]];
return filePath;
}
@end
相关文章推荐
- 精通iOS开发--第19章 Core Location 和 Map Kit 上
- iOS开发主流的数据解析框架JSONModel
- 不同BIOS下的U盘启动设置方法
- iOS Scrollview 的头部view的拉伸伸缩效果
- iOS-解压zip
- iOS-高德地图
- 敲一下enter键,完成iOS的打包工作
- 打造轻量级 tableViewController 之抽离 DataSource/Delegate
- IOS常用代码总结 - 第三方库部分
- iOS开发经验总结
- (翻译)开始iOS 7中自动布局教程(二)
- 开始iOS 7中自动布局教程(一)
- iOS architecture and framework(Stanford class 1)
- iOS 浅拷贝和深拷贝的区别? copy和mutableCopy的区别?
- 看完就彻底懂了session和cookie
- iOS 隐藏tabbar代码详解
- IOS TabBar判断登录
- iOS 利用 Autolayout 实现 view 间隔自动调整
- iOS_解析XML :KissXML、XmlReader
- NSString拼接字符串