【问题标题】:Get location name from Latitude & Longitude in iOS从 iOS 中的纬度和经度获取位置名称
【发布时间】:2013-05-14 22:06:27
【问题描述】:

我想从经纬度中查找当前位置名称,

这是我尝试过的代码 sn-p,但我的日志在除 placemarkplacemark.ISOcountryCodeplacemark.country 之外的所有地方都显示空值

我想要 placemark.localityplacemark.subLocality 的值,但它显示的是空值。

- (void)viewWillAppear:(BOOL)animated
{
     [super viewWillAppear:animated];

    // this creates the CCLocationManager that will find your current location
    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
    [locationManager startUpdatingLocation];

}

// this delegate is called when the app successfully finds your current location
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder reverseGeocodeLocation:locationManager.location
                   completionHandler:^(NSArray *placemarks, NSError *error) {
                       NSLog(@"reverseGeocodeLocation:completionHandler: Completion Handler called!");

                       if (error){
                           NSLog(@"Geocode failed with error: %@", error);
                           return;

                       }

                       NSLog(@"placemarks=%@",[placemarks objectAtIndex:0]);
                       CLPlacemark *placemark = [placemarks objectAtIndex:0];

                       NSLog(@"placemark.ISOcountryCode =%@",placemark.ISOcountryCode);
                       NSLog(@"placemark.country =%@",placemark.country);
                       NSLog(@"placemark.postalCode =%@",placemark.postalCode);
                       NSLog(@"placemark.administrativeArea =%@",placemark.administrativeArea);
                       NSLog(@"placemark.locality =%@",placemark.locality);
                       NSLog(@"placemark.subLocality =%@",placemark.subLocality);
                       NSLog(@"placemark.subThoroughfare =%@",placemark.subThoroughfare);

                   }];
}

// this delegate method is called if an error occurs in locating your current location
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    NSLog(@"locationManager:%@ didFailWithError:%@", manager, error);
}

提前致谢。

编辑:

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];

    CLLocation *currentLocation = newLocation;

    if (currentLocation != nil)
        NSLog(@"longitude = %.8f\nlatitude = %.8f", currentLocation.coordinate.longitude,currentLocation.coordinate.latitude);

    // stop updating location in order to save battery power
    [locationManager stopUpdatingLocation];


    [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error)
     {
         NSLog(@"Found placemarks: %@, error: %@", placemarks, error);
         if (error == nil && [placemarks count] > 0)
         {
             CLPlacemark *placemark = [placemarks lastObject];

             // strAdd -> take bydefault value nil
             NSString *strAdd = nil;

             if ([placemark.subThoroughfare length] != 0)
                 strAdd = placemark.subThoroughfare;

             if ([placemark.thoroughfare length] != 0)
             {
                 // strAdd -> store value of current location
                 if ([strAdd length] != 0)
                     strAdd = [NSString stringWithFormat:@"%@, %@",strAdd,[placemark thoroughfare]];
                 else
                 {
                     // strAdd -> store only this value,which is not null
                     strAdd = placemark.thoroughfare;
                 }
             }

             if ([placemark.postalCode length] != 0)
             {
                 if ([strAdd length] != 0)
                     strAdd = [NSString stringWithFormat:@"%@, %@",strAdd,[placemark postalCode]];
                 else
                     strAdd = placemark.postalCode;
             }

             if ([placemark.locality length] != 0)
             {
                 if ([strAdd length] != 0)
                     strAdd = [NSString stringWithFormat:@"%@, %@",strAdd,[placemark locality]];
                 else
                     strAdd = placemark.locality;
             }

             if ([placemark.administrativeArea length] != 0)
             {
                 if ([strAdd length] != 0)
                     strAdd = [NSString stringWithFormat:@"%@, %@",strAdd,[placemark administrativeArea]];
                 else
                     strAdd = placemark.administrativeArea;
             }

             if ([placemark.country length] != 0)
             {
                 if ([strAdd length] != 0)
                     strAdd = [NSString stringWithFormat:@"%@, %@",strAdd,[placemark country]];
                 else
                     strAdd = placemark.country;
             }
         }
     }];
}

【问题讨论】:

  • 您需要使用一些第三方 API,例如 Google Places API
  • 无需使用 Google 的付费服务 - 此功能已内置于 iOS。查看 CLLocation 和 CLPlacemark。它将为您提供您希望从坐标中获得的任何级别的粒度,例如。国家、城市、地区、时区等

标签: iphone ios ipad cllocationmanager reverse-geocoding


【解决方案1】:

我给你的是我用来解析地址的 sn-p。我还在必要的地方添加了评论,以便为您理解代码。除此之外,如果您有任何不明白的地方,请随时向 sn-p 提出任何问题。

didUpdateToLocation方法中写下sn-p

NSLog(@"didUpdateToLocation: %@", newLocation);
CLLocation *currentLocation = newLocation;

if (currentLocation != nil)
    NSLog(@"longitude = %.8f\nlatitude = %.8f", currentLocation.coordinate.longitude,currentLocation.coordinate.latitude);

// stop updating location in order to save battery power
[locationManager stopUpdatingLocation];


// Reverse Geocoding
NSLog(@"Resolving the Address");

// “reverseGeocodeLocation” method to translate the locate data into a human-readable address.

// The reason for using "completionHandler" ----
   //  Instead of using delegate to provide feedback, the CLGeocoder uses “block” to deal with the response. By using block, you do not need to write a separate method. Just provide the code inline to execute after the geocoding call completes.

[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error)
 {
    NSLog(@"Found placemarks: %@, error: %@", placemarks, error);
    if (error == nil && [placemarks count] > 0)
    {
        placemark = [placemarks lastObject];

        // strAdd -> take bydefault value nil
        NSString *strAdd = nil;

        if ([placemark.subThoroughfare length] != 0)
            strAdd = placemark.subThoroughfare;

        if ([placemark.thoroughfare length] != 0)
        {
            // strAdd -> store value of current location
            if ([strAdd length] != 0)
                strAdd = [NSString stringWithFormat:@"%@, %@",strAdd,[placemark thoroughfare]];
            else
            {
            // strAdd -> store only this value,which is not null
                strAdd = placemark.thoroughfare;
            }
        }

        if ([placemark.postalCode length] != 0)
        {
            if ([strAdd length] != 0)
                strAdd = [NSString stringWithFormat:@"%@, %@",strAdd,[placemark postalCode]];
            else
                strAdd = placemark.postalCode;
        }

        if ([placemark.locality length] != 0)
        {
            if ([strAdd length] != 0)
                strAdd = [NSString stringWithFormat:@"%@, %@",strAdd,[placemark locality]];
            else
                strAdd = placemark.locality;
        }

        if ([placemark.administrativeArea length] != 0)
        {
            if ([strAdd length] != 0)
                strAdd = [NSString stringWithFormat:@"%@, %@",strAdd,[placemark administrativeArea]];
            else
                strAdd = placemark.administrativeArea;
        }

        if ([placemark.country length] != 0)
        {
            if ([strAdd length] != 0)
                strAdd = [NSString stringWithFormat:@"%@, %@",strAdd,[placemark country]];
            else
                strAdd = placemark.country;
        }

strAdd 将使用地理位置返回地址..

享受编程!

【讨论】:

  • currentLocation 未知
  • currentLocation 是这个方法的 newLocation .. 检查我更新的答案
  • 嘿,我已经为你做了一切。您只需将 - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation 中的代码替换为我的代码,您就会得到答案。
  • 我收到类似placemarks.subThoroughfare not found in NSAraay 的错误。
  • 你是否集成了corelocation.framework,因为这个变量只存在于那个框架中
【解决方案2】:

带有完成块的方法:

typedef void(^addressCompletion)(NSString *);

-(void)getAddressFromLocation:(CLLocation *)location complationBlock:(addressCompletion)completionBlock
{
    __block CLPlacemark* placemark;
    __block NSString *address = nil;

    CLGeocoder* geocoder = [CLGeocoder new];
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error)
     {
         if (error == nil && [placemarks count] > 0)
         {
             placemark = [placemarks lastObject];
             address = [NSString stringWithFormat:@"%@, %@ %@", placemark.name, placemark.postalCode, placemark.locality];
             completionBlock(address);
         }
     }];
}

这是如何使用它:

CLLocation* eventLocation = [[CLLocation alloc] initWithLatitude:_latitude longitude:_longitude];

[self getAddressFromLocation:eventLocation complationBlock:^(NSString * address) {
        if(address) {
            _address = address;
        }
    }];

【讨论】:

    【解决方案3】:

    我在 Swift 3 中实现了 Niru 的解决方案,如果有人需要,请在此处发布:

    let geocoder = CLGeocoder()
    geocoder.reverseGeocodeLocation(self.location!) { (placemarksArray, error) in
    
        if (placemarksArray?.count)! > 0 {
    
            let placemark = placemarksArray?.first
            let number = placemark!.subThoroughfare
            let bairro = placemark!.subLocality
            let street = placemark!.thoroughfare
    
            self.addressLabel.text = "\(street!), \(number!) - \(bairro!)"
        }
    }
    

    【讨论】:

      【解决方案4】:

      【讨论】:

      • 它不是免费的 API。
      【解决方案5】:

      如果您尝试获取的位置列在此列表中,则说明您的代码有问题..

      http://developer.apple.com/library/ios/#technotes/tn2289/_index.html#//apple_ref/doc/uid/DTS40011305

      否则 CLGeoCoder 没有其他国家/地区的地址。

      我遇到了同样的问题,所以我用它来获取地址.. 给出了一个非常准确的地址。

      http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true_or_false

      【讨论】:

        【解决方案6】:

        首先,过滤 didUpdateToLocation 中的位置,以防止使用缓存或错误的位置进行地理编码

        NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
        
        if (abs(locationAge) > 5.0) return;
        
        if (newLocation.horizontalAccuracy < 0) return;
        

        另外,尝试将 reverseGeoCoding 方法从 didUpdateToLocation 移开

        【讨论】:

        • 苹果演示样本也显示空值,为什么有任何想法? http://developer.apple.com/library/ios/#samplecode/GeocoderDemo/Introduction/Intro.html#//apple_ref/doc/uid/DTS40011097
        【解决方案7】:

        一旦你有一个位置的latitudelongitude 值,你就可以使用CLGeocoder 这是一个tutorial,可能会对您有所帮助。

        【讨论】:

        • iOS 5及以上版本均可使用
        • 苹果演示样本也显示空值,为什么有任何想法? http://developer.apple.com/library/ios/#samplecode/GeocoderDemo/Introduction/Intro.html#//apple_ref/doc/uid/DTS40011097
        • 苹果演示样本也显示空值,为什么有任何想法? http://developer.apple.com/library/ios/#samplecode/GeocoderDemo/Introduction/Intro.html#//apple_ref/doc/uid/DTS40011097
        • 您是在模拟器中尝试这个吗?如果是,请在设备上尝试此操作。
        【解决方案8】:

        使用此 API 获取数据并传递 lat 和 long 值。

        API for Geo location

        【讨论】:

        • 苹果演示样本也显示空值,为什么有任何想法? http://developer.apple.com/library/ios/#samplecode/GeocoderDemo/Introduction/Intro.html#//apple_ref/doc/uid/DTS40011097
        【解决方案9】:

        试试这个

        [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
                //..NSLog(@"Found placemarks: %@, error: %@", placemarks, error);
                if (error == nil && [placemarks count] > 0) {
                    placemark = [placemarks lastObject];
                    lblgetaddrees.text = [NSString stringWithFormat:@"%@,%@,%@,%@,%@,%@",
                                          placemark.subThoroughfare, placemark.thoroughfare,
                                          placemark.postalCode, placemark.locality,
                                          placemark.administrativeArea,
                                          placemark.country];
                } else {
                    //..NSLog(@"%@", error.debugDescription);
                }
            } ];
        

        【讨论】:

          【解决方案10】:

          在 Swift 4.1 和 Xcode 9.4.1 中,这是我的解决方案之一。这里我使用 geocode API 来获取完整的地址。有了这个 api,我也可以得到村名。

          我正在使用 reverseGeocodeLocation,但它没有获取村庄地址详细信息或村庄名称,它只获取城市名称附近的信息。 这是最好的解决方案之一......

          func getAddressForLatLng(latitude: String, longitude: String)  { // Call this function
          
               let url = NSURL(string: "https://maps.googleapis.com/maps/api/geocode/json?latlng=\(latitude),\(longitude)")//Here pass your latitude, longitude
               print(url!)
               let data = NSData(contentsOf: url! as URL)
          
               if data != nil {
                  let json = try! JSONSerialization.jsonObject(with: data! as Data, options: JSONSerialization.ReadingOptions.allowFragments) as! NSDictionary
                  print(json)
          
                  let status = json["status"] as! String
                  if status == "OK" {
          
                      if let result = json["results"] as? NSArray   {
          
                          if result.count > 0 {
                              if let addresss:NSDictionary = result[0] as? NSDictionary {
                                  if let address = addresss["address_components"] as? NSArray {
                                      var newaddress = ""
                                      var number = ""
                                      var street = ""
                                      var city = ""
                                      var state = ""
                                      var zip = ""
                                      var country = ""
          
                                      if(address.count > 1) {
                                          number =  (address.object(at: 0) as! NSDictionary)["short_name"] as! String
                                      }
                                      if(address.count > 2) {
                                          street = (address.object(at: 1) as! NSDictionary)["short_name"] as! String
                                      }
                                      if(address.count > 3) {
                                          city = (address.object(at: 2) as! NSDictionary)["short_name"] as! String
                                      }
                                      if(address.count > 4) {
                                          state = (address.object(at: 4) as! NSDictionary)["short_name"] as! String
                                      }
                                      if(address.count > 6) {
                                          zip =  (address.object(at: 6) as! NSDictionary)["short_name"] as! String
                                      }
                                      newaddress = "\(number) \(street), \(city), \(state) \(zip)"
                                      print(newaddress)
          
                                      // OR 
                                      //This is second type to fetch pincode, country, state like this type of data
          
                                      for i in 0..<address.count {
                                          print(((address.object(at: i) as! NSDictionary)["types"] as! Array)[0])
                                          if ((address.object(at: i) as! NSDictionary)["types"] as! Array)[0] == "postal_code" {
                                              zip =  (address.object(at: i) as! NSDictionary)["short_name"] as! String
                                          }
                                          if ((address.object(at: i) as! NSDictionary)["types"] as! Array)[0] == "country" {
                                              country =  (address.object(at: i) as! NSDictionary)["long_name"] as! String
                                          }
                                          if ((address.object(at: i) as! NSDictionary)["types"] as! Array)[0] == "administrative_area_level_1" {
                                              state =  (address.object(at: i) as! NSDictionary)["long_name"] as! String
                                          }
                                          if ((address.object(at: i) as! NSDictionary)["types"] as! Array)[0] == "administrative_area_level_2" {
                                              district =  (address.object(at: i) as! NSDictionary)["long_name"] as! String
                                          }
          
                                      }
          
                                  }
          
                              }
                          }
          
                      }
          
                  }
          
              }
          
          }
          

          这样调用这个函数

          self.getAddressForLatLng(latitude: "\(self.lat!)", longitude: "\(self.lng!)")
          

          【讨论】:

            【解决方案11】:

            斯威夫特 5

            import CoreLocation
            
            func printAddress() {
              if let lat = Double(30.710489), lat != 0.0, let long = Double(76.852386), long != 0.0 {
              // Create Location
              let location = CLLocation(latitude: lat, longitude: long)
              // Geocode Location
              CLGeocoder().reverseGeocodeLocation(location) { (placemarks, error) in
                       // Process Response
                       self.processResponse(withPlacemarks: placemarks, error: error)
                     }
                 }
            }
            
            private func processResponse(withPlacemarks placemarks: [CLPlacemark]?, error: Error?) {
                   var address = ""
                    if let error = error {
                        address = "Unable to Reverse Geocode Location (\(error))"
                    } else {
                        if let placemarks = placemarks, let placemark = placemarks.first {
                            address = placemark.compactAddress ?? ""
                        } else {
                            address = "No address found"
                        }
                    }
                    print(address)
                }
            extension CLPlacemark {
            var compactAddress: String? {
                if let name = name {
                    var result = name
            
                    if let street = thoroughfare {
                        result += ", \(street)"
                    }
                    if let city = locality {
                        result += ", \(city)"
                    }
                    if let postalCode = postalCode {
                        result += ", \(postalCode)"
                    }
                    if let country = country {
                        result += ", \(country)"
                    }
                    return result
                }
            
                return nil
            }
            }
            // 2nd Way
            
            func updateLocation(lat:Double,long:Double) {
                       CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: Double(lat), longitude: Double(long)), completionHandler: { (placemarks, error) -> Void in
                           if error != nil {
                               return
                           }
                           else {
                              var location = ""
                               let pm = placemarks![0]
                               if pm.addressDictionary!["FormattedAddressLines"] != nil    {
                                   location =  "\n" + (pm.addressDictionary!["FormattedAddressLines"] as! NSArray).componentsJoined(by: ", ")
                               }else{
                                   location = "\n" + "NO_ADDRESS_FOUND"
                               }
            
                           }
                           })
                   }
            

            【讨论】:

              【解决方案12】:

              这是从位置坐标(纬度、经度)获取地址的方法。

              您可以使用此代码从 LocationCoordinates 获取地址信息,例如城市、国家、邮政编码等

              func getReverSerGeoLocation(location : CLLocation) {
                  print("getting Address from Location cordinate")
              
                  CLGeocoder().reverseGeocodeLocation(location) {
                      placemarks , error in
                  
                      if error == nil && placemarks!.count > 0 {
                          guard let placemark = placemarks?.last else {
                              return
                          }
                          print(placemark.thoroughfare)
                          print(placemark.subThoroughfare)
                          print("postalCode :-",placemark.postalCode)
                          print("City :-",placemark.locality)
                          print("subLocality :-",placemark.subLocality)
                          print("subAdministrativeArea :-",placemark.subAdministrativeArea)
                          print("Country :-",placemark.country)
                      }
                  }
              }
              

              只需通过传递纬度经度作为参数调用上述方法,如下所示

                  getReverSerGeoLocation(location: CLLocation(latitude: 21.0225, longitude: 72.5714))
              

              希望这会有所帮助!

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2018-11-26
                • 2018-12-14
                • 1970-01-01
                • 1970-01-01
                • 2012-10-16
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多