0

I have a data set of stores. I am building an app using Swift to help people see which stores are closest to them. The data include the stores' addresses, but not their coordinates, so I need to make sure the coordinates are included in the data model to calculate distance.

I have tried several methods listed on Stack Overflow of calculating coordinates from addresses. While they're great for returning a location you can print out in a UI view file, I cannot get the location to save to a variable in said view file, let alone a variable in a data model.

This is the closest I got in terms of number of errors, after several hours' attempts:

import Foundation
import MapKit

class Store: Identifiable, Decodable {
    
    var id:UUID?
    var name:String
    var address:String
    
    var distance: CLLocation {
        getCoordinatesFromPlace(place: address)
    }
    func getCoordinatesFromPlace(place: String){
        
        let geoCoder = CLGeocoder()
        geoCoder.geocodeAddressString(place) { (placemarks, error) in
            guard
                let placemarks = placemarks,
                let location = placemarks.first?.location?.coordinate
            else {
                // handle no location found
                return
            }
            return location
        }
    }
}

The errors are "Cannot convert return expression of type '()' to return type 'CLLocation' (when calculating distance) and "Cannot convert value of type 'CLLocationCoordinate2D' to closure result type 'Void'" for the function.

I know I'm being stupid. Could someone help me be less stupid?

In a View file (because that's what the answers seemed to have been written for?) I have tried passing the function to another variable in the view setup. I have tried adding inout variables to the function that would contain the location data, and just called the function in the body. I tried this for all of the address-to-coordinate solutions because all of the solutions seemed to just lead to printing out the coordinates, rather than passing them to a variable.

**Edit: I thank whoever pointed me to Returning data from async call in Swift function. After multiple attempts to make it work, I do not believe it is the same question/answer. This is not creating an asynchronous call pulling data from elsewhere, this is taking data that have been pulled and creating a new property from them, using an asynchronous method. As much as I have tried applying the async await method in the recommended page to 1) the model, 2) my data pulling function, 3) the viewmodel I cannot make this work. The model claims this is not part of my initializer, the viewmodel says I can't apply the method to type 'DataServiceBookstores'. The closest I have come to it is moving it to my ViewModel. It is below. I get "'async' call in a function that does not support concurrency" **

import Foundation

import MapKit

class BookstoreModel:ObservableObject {

@Published var bookstores = [Bookstore]()

init() {
    
    let serviceBookstores = DataServiceBookstores()
    self.bookstores = DataServiceBookstores.getLocalDataBookstores()
    
    for r in self.bookstores {
        r.latitude = try! await getCoordinate(from: r.address)
        print(r.latitude)
    }
    
    func getCoordinate(from address: String) async throws -> Double {
        let geocoder = CLGeocoder()

        guard let location = try await geocoder.geocodeAddressString(address)
            .compactMap( { $0.location } )
            .first(where: { $0.horizontalAccuracy >= 0 } )
        else {
            throw CLError(.geocodeFoundNoResult)
        }

        return location.coordinate.latitude
    }

}

}

AzAzinZ
  • 21
  • 2

0 Answers0