工作中遇到关于地图定位的问题,现在就来总结一下,没接触这块之前一直觉得地图或者是百度地图都是很高大上的东西,非常的难,在百度以及自己试验过之后发现并没有想象中的那么困难。

我以前以为如果要使用百度定位就需要安装百度地图,其实不是的,苹果系统自带了定位功能,不需要依赖任何其他的定位软件就可以定位到具体的经纬度。百度地图也是在苹果系统自带的定位功能上进行了一些更强大的功能的封装,以便用户使用起来更加方便。

本文中主要实现通过定位获取的经纬度来得到具体街道详情,以及通过街道信息获得经纬度两种CoreLocation地理编码的方式,废话不多说,下面来讲解实现方式。

ios 地图 经纬度 苹果地图显示经纬度_定时器

首先导入定位需要用到的CoreLocation.framework框架;(选中项目名-》General-》Linked Frameworks and Libraries点那个+号搜出CoreLocation.framework确定)在.h文件里面引入头文件

<strong>#import <UIKit/UIKit.h>
#import "CoreLocation/CoreLocation.h"
@interface LocationViewController : UIViewController<CLLocationManagerDelegate>
@end</strong>



然后我们就来做一下定位的操作,

@interface LocationViewController ()
//位置管理
@property (strong, nonatomic) CLLocationManager *locationManager;
//定时器
@property (strong, nonatomic) NSTimer *timer;
@end



新建一个可以切换状态的按钮放在屏幕中间,同时初始化计时器(3秒执行一次,可循环):


- (void)viewDidLoad
{
    [super viewDidLoad];
    UIButton *offbtn = [UIButton buttonWithType:UIButtonTypeCustom];
    offbtn.frame = CGRectMake(110, 80, 100, 50);
    [offbtn setBackgroundColor:[UIColor redColor]];
    [offbtn setTitle:@"开启定位" forState:UIControlStateNormal];
    [offbtn setTitle:@"取消定位" forState:UIControlStateSelected];
    [offbtn addTarget:self action:@selector(changeState:) forControlEvents:UIControlEventTouchUpInside];
    [offbtn addTarget:self action:@selector(startTimer:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:offbtn];
    _timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(startLocation) userInfo:nil repeats:YES];

//    [self startLocation];
    // Do any additional setup after loading the view.
//将定时器加入到程序主循环中
//    [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
    //取消定时器,彻底关闭,定时器从主循环中移除
//    [_timer invalidate];
//    _timer = nil;
}




在这里我不把定时器加入主循环里面,我通过按钮切换来开启关闭计时器,要是想把定时器加入主循环中的可以使用上面的方法,就不需要再调用开启定时器的方法了。

假如是ios8的sdk就需要加判断,首先在Info.plist里面添加一个NSLocationAlwaysUsageDescription :YES如下:

ios 地图 经纬度 苹果地图显示经纬度_ios 地图 经纬度_02


- (void)changeState:(UIButton*)btn
{
    [btn setSelected:!btn.selected];
}
- (void)startTimer:(UIButton*)btn
{
    if (btn.selected) {
        //开启定时器
        [_timer setFireDate:[NSDate distantPast]];
    }else{
        //关闭定时器
        [_timer setFireDate:[NSDate distantFuture]];
    }
}
- (void)startLocation
{
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    //这里设置为最高精度定位
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    //设备移动10米通知代理器更新位置
    self.locationManager.distanceFilter = 10.0f;<p style="margin-top: 0px; margin-bottom: 0px; font-size: 11px; font-family: Menlo;">    <span style="color: #bb2ca2">if</span> (<span style="color: #78492a">iOS8</span>) {</p><p style="margin-top: 0px; margin-bottom: 0px; font-size: 11px; font-family: Menlo; color: rgb(0, 132, 0);"><span style="color: #000000"> </span>//        [self.locationManager requestWhenInUseAuthorization];// <span style="font-family: 'Heiti SC Light';">前台定位</span></p><p style="margin-top: 0px; margin-bottom: 0px; font-size: 11px; font-family: Menlo; color: rgb(61, 29, 129);"><span style="color: #000000">      <span >	</span>[</span><span style="color: #bb2ca2">self</span><span style="color: #000000">.</span><span style="color: #4f8187">locationManager</span><span style="color: #000000"> </span>requestAlwaysAuthorization<span style="color: #000000">];</span><span style="color: #008400">// </span><span style="font-family: 'Heiti SC Light'; color: rgb(0, 132, 0);">前后台同时定位</span></p><p style="margin-top: 0px; margin-bottom: 0px; font-size: 11px; font-family: Menlo;">    }</p>    //启动定位
    [self.locationManager startUpdatingLocation];
    
}
//定位代理经纬度回调
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    //此处locations存储了持续更新的位置坐标值,取最后一个值为最新位置,如果不想让其持续更新位置,则在此方法中获取到一个值之后让locationManager stopUpdatingLocation
    
//    CLLocation *currentLocation = [locations lastObject];
    CLLocation *currentLocation = [[CLLocation alloc]initWithLatitude:31.00927 longitude:121.40582];//如果使用模拟器不能定位的机器
    NSLog(@"%@",[NSString stringWithFormat:@"纬度:%3.5f\n经度:%3.5f",currentLocation.coordinate.latitude,currentLocation.coordinate.longitude]);
    // 获取当前所在的城市名
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    //根据经纬度反向地理编译出地址信息
    [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error)
    
    {
        for (CLPlacemark * placemark in placemarks) {
            
            NSString *city = placemark.locality;
            if (!city) {
                //四大直辖市的城市信息无法通过locality获得,只能通过获取省份的方法来获得(如果city为空,则可知为直辖市)
                city = placemark.administrativeArea;
            }
            NSLog(@"address = %@\n",placemark.name);
            NSDictionary *dictionary = [placemark addressDictionary];
            //  Country(国家)  State(省) locality(市) SubLocality(区)
            NSLog(@"%@%@%@",[dictionary objectForKey:@"State"], city,placemark.subLocality);
        }
        if (error == nil && [placemarks count] == 0)
        {
            NSLog(@"No results were returned.");
        }
        else if (error != nil)
        {
            NSLog(@"An error occurred = %@", error);
        }  
    }];
    
    //系统会一直更新数据,直到选择停止更新,因为我们只需要获得一次经纬度即可,所以获取之后就停止更新
    
    [manager stopUpdatingLocation];
}

需要获取其他的信息可以到CLPlacemark里面最下面去找自己想要的信息,不知道意思可以全部打印出来然后再取舍,下面再通过已知的位置来获取经纬度信息

插一点调试的小问题:如果用真机调试的话就可以用[location lastObject],我用模拟器调试就会自己制定一个经纬度运行,这里要选中模拟器,在调试-》位置-》自定位置里面随便输入一个(操作如下),这里不指定还是有问题,下面的一个网友说的很详细,我用的是无线网,也不知道是不是这个问题,大家自定义地址凑合着调试。

http://www.crifan.com/use_clgeocoder_reversegeocodelocation_return_nil_and_error_kclerrordomain_in_virtualbox_mac_xcode_ios_emulator/

ios 地图 经纬度 苹果地图显示经纬度_ios 地图 经纬度_03


下面地理位置编码,我直接加了一个方法,直接把startLocation改成下面的方法名就可以了:

- (void)geocode
{
    //1.输入的要定位的地址
    NSString *address = @"上海市闵行区江川路690号";
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
        if (error || placemarks.count == 0) {
            return ;
        }else {//编码成功
            for (CLPlacemark *placemark in placemarks) {
                NSString *city = placemark.locality;
                if (!city) {
                    //四大直辖市的城市信息无法通过locality获得,只能通过获取省份的方法来获得(如果city为空,则可知为直辖市)
                    city = placemark.administrativeArea;
                }
                NSLog(@"address = %@\n",placemark.name);
                NSDictionary *dictionary = [placemark addressDictionary];
                //  Country(国家)  State(省) locality(市) SubLocality(区)
                NSLog(@"地理编码:%@%@%@",[dictionary objectForKey:@"State"], city,placemark.subLocality);
            }
            //取出获取的地理信息数组中的最后定位的
            CLPlacemark *lastPlacemark = [placemarks lastObject];
            CLLocationDegrees latitude = lastPlacemark.location.coordinate.latitude;
            CLLocationDegrees longitude = lastPlacemark.location.coordinate.longitude;
            NSLog(@"%@",[NSString stringWithFormat:@"纬度:%3.5f\n经度:%3.5f",latitude,longitude]);
        }
    }];
}



打印结果如下(3秒定位一次):

ios 地图 经纬度 苹果地图显示经纬度_ios 地图 经纬度_04