Search code examples
swiftuimapkitmapkitannotation

Convert adress input in annotation on the map - SwiftUI


I am a beginner so sorry for my question.

I have a map and annotations in a Datas file.

Now I would like the user to be able to register an address with a form.

How do I go from a normal address to a

location: CLLocationCoordinate2D(latitude: 48.8566, longitude: 2.3522)

Thanks for your help


Solution

  • Core Location has a "geocoder", which is what would take a street address and convert it to a CLLocationCoordinate2D.

    This is from the official Apple documentation (https://developer.apple.com/documentation/corelocation/converting_between_coordinates_and_user-friendly_place_names):

    func getCoordinate( addressString : String, 
            completionHandler: @escaping(CLLocationCoordinate2D, NSError?) -> Void ) {
        let geocoder = CLGeocoder()
        geocoder.geocodeAddressString(addressString) { (placemarks, error) in
            if error == nil {
                if let placemark = placemarks?[0] {
                    let location = placemark.location!
                        
                    completionHandler(location.coordinate, nil)
                    return
                }
            }
                
            completionHandler(kCLLocationCoordinate2DInvalid, error as NSError?)
        }
    }
    

    Note that the preceding function uses callback functions and is an asynchronous function. That means that it does not return immediately -- instead, it finishes at an indeterminate time in the future and calls the callback function when it is finished.


    Since you tagged the question SwiftUI, the following is a trivial example with SwiftUI:

    import SwiftUI
    import MapKit
    
    class LocationManager : ObservableObject {
        @Published var location : CLLocationCoordinate2D?
        
        func convertAddress(address: String) {
            getCoordinate(addressString: address) { (location, error) in
                if error != nil {
                    //handle error
                    return
                }
                DispatchQueue.main.async {
                    self.location = location
                }
            }
        }
        
        private func getCoordinate(addressString : String,
                completionHandler: @escaping(CLLocationCoordinate2D, NSError?) -> Void ) {
            let geocoder = CLGeocoder()
            geocoder.geocodeAddressString(addressString) { (placemarks, error) in
                if error == nil {
                    if let placemark = placemarks?[0] {
                        let location = placemark.location!
                            
                        completionHandler(location.coordinate, nil)
                        return
                    }
                }
                    
                completionHandler(kCLLocationCoordinate2DInvalid, error as NSError?)
            }
        }
    }
    
    struct ContentView: View {
        @State var addressString = "1600 Pennsylvania Ave, Washington D.C."
        @StateObject private var locationManager = LocationManager()
        
        var body: some View {
            VStack {
                Text("Address: \(addressString)")
                if let location = locationManager.location {
                    Text("Lat: \(location.latitude) Long: \(location.longitude)")
                }
            }.onAppear {
                locationManager.convertAddress(address: addressString)
            }
        }
    }