Swift - Generate an Address Format from Reverse Geocoding

前端 未结 10 1402
难免孤独
难免孤独 2021-01-31 03:46

I am trying to generate a Formatted Full address using CLGeocoder in Swift 3. I referred to this SO thread to get the code given below.

However, sometimes the app crashe

相关标签:
10条回答
  • 2021-01-31 04:21

    I create my own static class for Geocoding and get attributes of CLPlacemark and obtain a complete address, like "usually" returns Google:

    import Foundation
    import CoreLocation
    
    class ReverseGeocoding {
    
        static func geocode(latitude: Double, longitude: Double, completion: @escaping (CLPlacemark?, _ completeAddress: String?, Error?) -> ())  {
            CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: latitude, longitude: longitude)) { placemarks, error in
                guard let placemark = placemarks?.first, error == nil else {
                    completion(nil, nil, error)
                    return
                }
    
                let completeAddress = getCompleteAddress(placemarks)
    
                completion(placemark, completeAddress, nil)
            }
        }
    
        static private func getCompleteAddress(_ placemarks: [CLPlacemark]?) -> String {
            guard let placemarks = placemarks else {
                return ""
            }
    
            let place = placemarks as [CLPlacemark]
            if place.count > 0 {
                let place = placemarks[0]
                var addressString : String = ""
                if place.thoroughfare != nil {
                    addressString = addressString + place.thoroughfare! + ", "
                }
                if place.subThoroughfare != nil {
                    addressString = addressString + place.subThoroughfare! + ", "
                }
                if place.locality != nil {
                    addressString = addressString + place.locality! + ", "
                }
                if place.postalCode != nil {
                    addressString = addressString + place.postalCode! + ", "
                }
                if place.subAdministrativeArea != nil {
                    addressString = addressString + place.subAdministrativeArea! + ", "
                }
                if place.country != nil {
                    addressString = addressString + place.country!
                } 
    
                return addressString
            }
            return ""
        }
    }
    

    Then the implementation:

        ReverseGeocoding.geocode(coordinate: coordinate, completion: { (placeMark, completeAddress, error) in
    
            if let placeMark = placeMark, let completeAddress = completeAddress {
                print(placeMark.postalCode)
                print(placeMark)
                print(completeAddress)
            } else {
                // do something with the error
            }
    

    Finaly the print:

    15172
    Calle del Arenal, 4, Calle del Arenal, 4, 15172 Oleiros, A Coruña, España @ <+43.33190337,-8.37144380> +/- 100.00m, region CLCircularRegion (identifier:'<+43.33190337,-8.37144380> radius 70.84', center:<+43.33190337,-8.37144380>, radius:70.84m)
    Calle del Arenal, 4, Oleiros, 15172, A Coruña, España
    
    0 讨论(0)
  • 2021-01-31 04:22
    CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: vehicleLocation.latitude, longitude: vehicleLocation.latitude), completionHandler: {(placemarks, error) -> Void in
    
      guard error == nil else {completionHandler(nil); return}
    
      guard let place = placemarks else {completionHandler(nil); return}
    
      if place.count > 0 {
        let pm = place[0]
    
        var addArray:[String] = []
        if let name = pm.name {
          addArray.append(name)
        }
        if let thoroughfare = pm.thoroughfare {
          addArray.append(thoroughfare)
        }
        if let subLocality = pm.subLocality {
          addArray.append(subLocality)
        }
        if let locality = pm.locality {
          addArray.append(locality)
        }
        if let subAdministrativeArea = pm.subAdministrativeArea {
          addArray.append(subAdministrativeArea)
        }
        if let administrativeArea = pm.administrativeArea {
          addArray.append(administrativeArea)
        }
        if let country = pm.country {
          addArray.append(country)
        }
        if let postalCode = pm.postalCode {
          addArray.append(postalCode)
        }
    
        let addressString = addArray.joined(separator: ",\n")
    
        print(addressString)
    
        completionHandler(addressString)
      }
      else { completionHandler(nil)}
    })
    
    0 讨论(0)
  • 2021-01-31 04:22
    func convertLatLongToAddress(latitude:Double, longitude:Double) {
        let geoCoder = CLGeocoder()
        let location = CLLocation(latitude: latitude, longitude: longitude)
        var labelText = ""
        geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
    
            var placeMark: CLPlacemark!
            placeMark = placemarks?[0]
    
            if placeMark != nil {
                if let name = placeMark.name {
                    labelText = name
                }
                if let subThoroughfare = placeMark.subThoroughfare {
                    if (subThoroughfare != placeMark.name) && (labelText != subThoroughfare) {
                        labelText = (labelText != "") ? labelText + "," + subThoroughfare : subThoroughfare
                    }
                }
                if let subLocality = placeMark.subLocality {
                    if (subLocality != placeMark.subThoroughfare) && (labelText != subLocality) {
                        labelText = (labelText != "") ? labelText + "," + subLocality : subLocality
                    }
                }
                if let street = placeMark.thoroughfare {
                    if (street != placeMark.subLocality) && (labelText != street) {
                        labelText = (labelText != "") ? labelText + "," + street : street
                    }
                }
                if let locality = placeMark.locality {
                    if (locality != placeMark.thoroughfare) && (labelText != locality) {
                        labelText = (labelText != "") ? labelText + "," + locality : locality
                    }
                }
                if let city = placeMark.subAdministrativeArea {
                    if (city != placeMark.locality) && (labelText != city) {
                        labelText = (labelText != "") ? labelText + "," + city : city
                    }
                }
                if let state = placeMark.postalAddress?.state {
                    if (state != placeMark.subAdministrativeArea) && (labelText != state) {
                        labelText = (labelText != "") ? labelText + "," + state : state
                    }
    
                }
                if let country = placeMark.country {
                    labelText = (labelText != "") ? labelText + "," + country : country
                }
                // labelText gives you the address of the place
            }
        })
    }
    

    Here as an improvement I added place name as well. It makes address more meaningful.

    0 讨论(0)
  • 2021-01-31 04:28

    Keeping it simple - A full Swift 3 & 4 compatible View Controller example for obtaining a formatted address string from user's location (add in the other keys available in CLPlacemark if you want more information in your string):

    import UIKit
    import CoreLocation
    
    class ViewController: UIViewController, CLLocationManagerDelegate {
    
    let manager = CLLocationManager()
    let geocoder = CLGeocoder()
    
    var locality = ""
    var administrativeArea = ""
    var country = ""
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        manager.delegate = self
        manager.desiredAccuracy = kCLLocationAccuracyBest
        manager.requestWhenInUseAuthorization()
        manager.startUpdatingLocation()
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
            let location = locations[0]
            manager.stopUpdatingLocation()
    
        geocoder.reverseGeocodeLocation(location, completionHandler: {(placemarks, error) in
            if (error != nil) {
                print("Error in reverseGeocode")
                }
    
            let placemark = placemarks! as [CLPlacemark]
            if placemark.count > 0 {
                let placemark = placemarks![0]
                self.locality = placemark.locality!
                self.administrativeArea = placemark.administrativeArea!
                self.country = placemark.country!
            }
        })
    }
    
    func userLocationString() -> String {
        let userLocationString = "\(locality), \(administrativeArea), \(country)"
        return userLocationString
    }
    
    }
    

    Calling print(userLocationString()) in this example will print: suburb, state, country

    Don't forget to add Privacy - Location When In Use Usage Description to your Info.plist file beforehand, to allow the user to grant permissions to your app to utilise location services.

    0 讨论(0)
  • 2021-01-31 04:28

    Here's a 2-3 line version of the answers here:

        func getAddress(placemarks: [CLPlacemark]) -> String {
            guard let placemark = placemarks.first, !placemarks.isEmpty else {return ""}
            let outputString = [placemark.locality,
                                placemark.subLocality,
                                placemark.thoroughfare,
                                placemark.postalCode,
                                placemark.subThoroughfare,
                                placemark.country].compactMap{$0}.joined(separator: ", ")
            print(outputString)
            return outputString
        }
    
    0 讨论(0)
  • 2021-01-31 04:29
    func getAddressFromLatLon(pdblLatitude: String, withLongitude pdblLongitude: String) {
            var center : CLLocationCoordinate2D = CLLocationCoordinate2D()
            let lat: Double = Double("\(pdblLatitude)")!
            //21.228124
            let lon: Double = Double("\(pdblLongitude)")!
            //72.833770
            let ceo: CLGeocoder = CLGeocoder()
            center.latitude = lat
            center.longitude = lon
    
            let loc: CLLocation = CLLocation(latitude:center.latitude, longitude: center.longitude)
    
    
            ceo.reverseGeocodeLocation(loc, completionHandler:
                {(placemarks, error) in
                    if (error != nil)
                    {
                        print("reverse geodcode fail: \(error!.localizedDescription)")
                    }
                    let pm = placemarks! as [CLPlacemark]
    
                    if pm.count > 0 {
                        let pm = placemarks![0]
                        print(pm.country)
                        print(pm.locality)
                        print(pm.subLocality)
                        print(pm.thoroughfare)
                        print(pm.postalCode)
                        print(pm.subThoroughfare)
                        var addressString : String = ""
                        if pm.subLocality != nil {
                            addressString = addressString + pm.subLocality! + ", "
                        }
                        if pm.thoroughfare != nil {
                            addressString = addressString + pm.thoroughfare! + ", "
                        }
                        if pm.locality != nil {
                            addressString = addressString + pm.locality! + ", "
                        }
                        if pm.country != nil {
                            addressString = addressString + pm.country! + ", "
                        }
                        if pm.postalCode != nil {
                            addressString = addressString + pm.postalCode! + " "
                        }
    
    
                        print(addressString)
                  }
            })
    
        }
    
    0 讨论(0)
提交回复
热议问题