2017-05-17 8 views
8

나는 Swift3 에있는 응용 프로그램에서 일하고 있습니다. 나는 그것에 대한 답을 찾을 수없는 문자 문제가 있습니다.Swift에서 위도와 경도의 도시 이름과 나라 찾기

위도와 경도를 기반으로 도시 이름과 국가 짧은 이름을 어떻게 알 수 있습니까?

import UIKit 
import CoreLocation 

class ViewController: UIViewController, CLLocationManagerDelegate{ 
    let locationManager = CLLocationManager() 
    var latitude: Double = 0 
    var longitude: Double = 0 
    override func viewDidLoad() { 
     super.viewDidLoad() 
     // For use when the app is open & in the background 
     locationManager.requestAlwaysAuthorization() 
     // For use when the app is open 
     //locationManager.requestWhenInUseAuthorization() 
     locationManager.delegate = self 
     locationManager.startUpdatingLocation() 
     if CLLocationManager.locationServicesEnabled() { 
      locationManager.delegate = self 
      locationManager.desiredAccuracy = kCLLocationAccuracyBest 
      locationManager.startUpdatingLocation() 
     } 
    } 
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { 
     if let location = locations.first { 
      print(location.coordinate) 
      latitude = location.coordinate.latitude 
      longitude = location.coordinate.longitude 
     } 
    } 
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { 
     if (status == CLAuthorizationStatus.denied){ 
      showLocationDisabledpopUp() 
     } 
    } 
    func showLocationDisabledpopUp() { 
     let alertController = UIAlertController(title: "Background Location Access Disabled", message: "We need your location", preferredStyle: .alert) 
     let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) 
     alertController.addAction(cancelAction) 
     let openAction = UIAlertAction(title: "Open Setting", style: .default) { (action) in 
      if let url = URL(string: UIApplicationOpenSettingsURLString){ 
       UIApplication.shared.open(url, options: [:], completionHandler: nil) 
      } 
     } 
     alertController.addAction(openAction) 
     self.present(alertController, animated: true, completion: nil) 
    } 
} 
+0

https://developer.apple.com/reference/corelocation/clgeocoder – dan

답변

11

프로젝트에 Google Maps API을 통합하는 것이 좋습니다. 그렇다면 Google에서 제공하는 Reverse Geocoding을 사용하여 작업을 수행 할 수 있습니다.

또한 Google에는 IOS 개발을 위해 Google Maps SDK이 있으며 고려해야 할 가치가 있습니다.

UPD :지도를 프로젝트에 통합하지 않고도이 작업을 수행 할 수 있습니다. this 대답에 따라, 당신은 Google API에 HTTP 요청을 사용하여 달성 할 수 있습니다. 요청 사항 :

https://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&key=API_KEY 

는 국가 및 도시 이름을 포함하여 요청 된 장소에 대한 정보 JSON 객체를 반환합니다.

나는 Swift에서 http 요청을하려면 Alamofire을 사용하는 것이 좋습니다.

+0

내 프로젝트에지도를 삽입하지 마십시오.이 코드는 [this] (http ://)에 기초하여 위도와 경도 인 –

+0

@A.Ali에 사용합니다. /image/sapa/32758343/4511620) 대답,지도를 통합하지 않고도 쉽게 Google API를 사용할 수 있습니다. http 요청을하기 위해 'Alamofire'만 사용하면됩니다. –

+0

@AAli, 내 업데이트 된 질문보기 –

3

CoreLocation의 CLGeocoder을 사용할 수 있습니다. Apple 설명서에서 (내 강조) :

지리적 좌표와 장소 이름 사이의 변환을위한 단일 샷 개체.

CLGeocoder 클래스는 좌표 (위도와 경도로 지정)와 사용자 친화적 인 좌표 표현 간의 변환 서비스를 제공합니다. 좌표 보통의 사용자 친화적 인 표현은, 거리로 구성 도시,이 서비스는 같은 MapKit에 관련이와

지정된 위치에 해당하는 주 및 국가 정보 ..., 앱에서지도를 사용/표시하지 않아도됩니다.

+0

'MKReverseGeocoder '는 몇 년 전에 사용되지 않았습니다. 'CLGeocoder'를 사용해야합니다. – dan

+0

물론, 당신 말이 맞아요;) –

+0

내 프로젝트에지도를 삽입하지 않아요. 위도와 경도로이 코드를 사용합니다. 링크를 사용하려면 국가 이름이 필요합니다. –

4

CLGeocoder reverseGeocodeLocation 메서드를 사용하여 CLPlacemark을 가져오고 countrylocality 속성 정보를 가져올 수 있습니다. 그것은 그 정보를 가져올 때 당신은 당신의 방법에 완료 핸들러를 추가해야합니다 때문에 비동기 방법 참고 :

func fetchCountryAndCity(location: CLLocation, completion: @escaping (String, String) ->()) { 
    CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in 
     if let error = error { 
      print(error) 
     } else if let country = placemarks?.first?.country, 
      let city = placemarks?.first?.locality { 
      completion(country, city) 
     } 
    } 
} 

사용이

let location = CLLocation(latitude: -22.963451, longitude: -43.198242) 

fetchCountryAndCity(location: location) { country, city in 
    print("country:", country) 
    print("city:", city) 
} 
+0

고맙습니다.하지만이 나라를 어떻게 찾을 수 있을까요? 이름 –

+0

https://developer.apple.com/reference/corelocation/clplacemark/1423796-isocountrycode 국가 대신 isocountrycode를 사용할 수 있습니다. –

8

당신이 역 지오 코딩이라고합니다 필요한 것은. 이미 일부 속성을 맨 위에 선언 했으므로당신은 CLGeocoder & CLPlancemark

let locationManager = CLLocationManager() 
var location: CLLocation? 

let geocoder = CLGeocoder() 
var placemark: CLPlacemark? 

// here I am declaring the iVars for city and country to access them later 

var city: String? 
var country: String? 
var countryShortName: String? 

당신이 위치

지오 코딩으로 완료되면

func startLocationManager() { 
    // always good habit to check if locationServicesEnabled 
    if CLLocationManager.locationServicesEnabled() { 
     locationManager.delegate = self 
     locationManager.desiredAccuracy = kCLLocationAccuracyBest 
     locationManager.startUpdatingLocation() 
    } 
} 

도 중지 다른를 만들 위치 서비스를 시작할 수있는 기능을 만들기를 추가해야

func stopLocationManager() { 
    locationManager.stopUpdatingLocation() 
    locationManager.delegate = nil 
} 

보기에서 didLoad 또는 fr 톰 어디서나 위치 관리자 didUpdateLocations의 대리자 메서드를 구현하는 위치 관리자는 먼저 체크

override func viewDidLoad() { 
super.viewDidLoad() 

    let authStatus = CLLocationManager.authorizationStatus() 
    if authStatus == .notDetermined { 
     locationManager.requestWhenInUseAuthorization() 
    } 

    if authStatus == .denied || authStatus == .restricted { 
     // add any alert or inform the user to to enable location services 
    } 

    // here you can call the start location function 
    startLocationManager() 

} 

위치 관리자의 대리자 메서드를 구현을 추가 didFailedWithError

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { 
    // print the error to see what went wrong 
    print("didFailwithError\(error)") 
    // stop location manager if failed 
    stopLocationManager() 
} 

을 시작하려는

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { 
    // if you need to get latest data you can get locations.last to check it if the device has been moved 
    let latestLocation = locations.last! 

    // here check if no need to continue just return still in the same place 
    if latestLocation.horizontalAccuracy < 0 { 
     return 
    } 
    // if it location is nil or it has been moved 
    if location == nil || location!.horizontalAccuracy > lastLocation.horizontalAccuracy { 

     location = lastLocation 
     // stop location manager 
     stopLocationManager() 

     // Here is the place you want to start reverseGeocoding 
     geocoder.reverseGeocodeLocation(lastLocation, completionHandler: { (placemarks, error) in 
       // always good to check if no error 
       // also we have to unwrap the placemark because it's optional 
       // I have done all in a single if but you check them separately 
       if error == nil, let placemark = placemarks, !placemark.isEmpty { 
        self.placemark = placemark.last 
       } 
       // a new function where you start to parse placemarks to get the information you need 
       self.parsePlacemarks() 

      }) 
    } 
} 

parsePlacemarks 함수를 추가하십시오.

parsePlacemarks() { 
    // here we check if location manager is not nil using a _ wild card 
    if let _ = location { 
     // unwrap the placemark 
     if let placemark = placemark { 
      // wow now you can get the city name. remember that apple refers to city name as locality not city 
      // again we have to unwrap the locality remember optionalllls also some times there is no text so we check that it should not be empty 
      if let city = placemark.locality, !city.isEmpty { 
       // here you have the city name 
       // assign city name to our iVar 
       self.city = city 
      } 
      // the same story optionalllls also they are not empty 
      if let country = placemark.country, !country.isEmpty { 

       self.country = country 
      } 
      // get the country short name which is called isoCountryCode 
      if let countryShortName = placemark.isoCountryCode, !countryShortName.isEmpty { 

       self.countryShortName = countryShortName 
      } 

     } 


    } else { 
     // add some more check's if for some reason location manager is nil 
    } 

} 

당신은 수를 가 subThoroughfare 자세한 내용은 문서를 계속 읽기라고한다 도로 &라고 + cmd를 사용하면 예를 들어 거리 이름에 액세스 할 수있는 모든 속성을 볼 수 CLPlacemark 클릭해야

참고 : 여기에 구현되지 않은 지오 코더 오류도 위치를 확인해야하지만 오류 코드와 오류 코드를 확인하는 가장 좋은 장소는 다른 곳에서 처리해야합니다.

업데이트 : 나는 국가와 동일하다 isoCountryCode을 추가하여 이미 위치 서비스를 사용하는 동안 API 및 Alamofire 구글 호출 여분의 네트워크를 추가 할 필요가 짧은 이름없는 경우 paresPlacemarks 기능을 확인

3

여기 스위프트 4 코드 :

var locationManager = CLLocationManager() 

    override func viewDidLoad() { 
    super.viewDidLoad() 
    locationManager.delegate = self 
    locationManager.requestWhenInUseAuthorization() 
    locationManager.desiredAccuracy = kCLLocationAccuracyBest 
    locationManager.startUpdatingLocation() 
    locationManager.startMonitoringSignificantLocationChanges() 
    // Here you can check whether you have allowed the permission or not. 
    if CLLocationManager.locationServicesEnabled() 
    { 
     switch(CLLocationManager.authorizationStatus()) 
     { 
     case .authorizedAlways, .authorizedWhenInUse: 
      print("Authorize.") 
      let latitude: CLLocationDegrees = (locationManager.location?.coordinate.latitude)! 
      let longitude: CLLocationDegrees = (locationManager.location?.coordinate.longitude)! 
      let location = CLLocation(latitude: latitude, longitude: longitude) //changed!!! 
      CLGeocoder().reverseGeocodeLocation(location, completionHandler: {(placemarks, error) -> Void in 
       if error != nil { 
        return 
       }else if let country = placemarks?.first?.country, 
        let city = placemarks?.first?.locality { 
        print(country) 
        self.cityNameStr = city 
       } 
       else { 
       } 
      }) 
      break 

     case .notDetermined: 
      print("Not determined.") 
      self.showAlertMessage(messageTitle: "Bolo Board", withMessage: "Location service is disabled!!") 
      break 

     case .restricted: 
      print("Restricted.") 
      self.showAlertMessage(messageTitle: "Bolo Board", withMessage: "Location service is disabled!!") 
      break 

     case .denied: 
      print("Denied.") 
     } 
    } 
} 

func showAlertMessage(messageTitle: NSString, withMessage: NSString) ->Void { 
    let alertController = UIAlertController(title: messageTitle as String, message: withMessage as String, preferredStyle: .alert) 
    let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action:UIAlertAction!) in 

    } 
    alertController.addAction(cancelAction) 

    let OKAction = UIAlertAction(title: "Settings", style: .default) { (action:UIAlertAction!) in 
     if let url = URL(string: "App-Prefs:root=Privacy&path=LOCATION/com.company.AppName") { 
      if #available(iOS 10.0, *) { 
       UIApplication.shared.open(url, options: [:], completionHandler: nil) 
      } else { 
       // Fallback on earlier versions 
      } 
     } 
    } 
    alertController.addAction(OKAction) 
    self.present(alertController, animated: true, completion:nil) 
} 
0

동일한 문제가 있습니다.이 코드를 사용할 수 있습니다.

func placePicker(_ viewController: GMSPlacePickerViewController, didPick place: GMSPlace) { 

    viewController.dismiss(animated: true, completion: nil) 
    let geoCoder = CLGeocoder() 
    let location = CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude) 
    geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in 

     // Place details 
     var placeMark: CLPlacemark! 
     placeMark = placemarks?[0] 

     // Address dictionary 
     print(placeMark.addressDictionary as Any) 
    // 

    print("Place name \(place.name)") 
    print("Place address \(String(describing: place.formattedAddress))") 
    print("Place attributions \(String(describing: place.attributions))") 



}) 
} 

이렇게하면 문제가 해결 될 것입니다.