I am working in Swift trying to update an organization struct that will need to hold a latitude and longitude. I created a mutating function in the struct that will update the latitude and longitude based on the organization organization struct’s address. I got it to work, but the issue is that when I call the mutating function, I need to manually enter the variable name with the .latitude and .longitude. Is there a way that I can pass the variable struct’s name automatically and reference the .latitude and .longitude without calling the specific variable name with it so I can make it more usable? I included an example below with my code. Thanks for your help!
import UIKit
import PlaygroundSupport
import CoreLocation
PlaygroundPage.current.needsIndefiniteExecution = true
struct organization {
var name: String
var address: String
var latitude: CLLocationDegrees = 0 //default setting for latitude
var longitude: CLLocationDegrees = 0 //default setting for longitude
mutating func getCoordinateFrom(completion: @escaping(_ coordinate: CLLocationCoordinate2D?, _ error: Error?) -> () ) {
CLGeocoder().geocodeAddressString(address) { placemarks, error in
completion(placemarks?.first?.location?.coordinate, error)
}
}
}
struct Coordinates {
var latitude: Double
var longitude: Double
}
//create an wildernessLodge variable of type organization
var wildernessLodge = organization(name: "Disney's Wilderness Lodge", address: "901 Timberline Dr, Orlando, FL 32830")
wildernessLodge.getCoordinateFrom { coordinate, error in
guard let coordinate = coordinate, error == nil else { return }
wildernessLodge.latitude = coordinate.latitude
wildernessLodge.longitude = coordinate.longitude
print("update 1 \(wildernessLodge)")
}
I'm a bit confused by your code. Why is
getCoordinateFrommarked asmutating? Perhaps you meant to write something like this.Now this function is mutating (it modifies
self), andcan be replaced with
The only reason to leave the
getCoordinateFrommethod is if, somewhere in your code, you intend to get coordinates from an address but not update the coordinates in the struct. I can't imagine a good reason to do that, so I would recommend replacing thegetCoordinateFrommethod with something else.Alternatively, if you generally intend to set the coordinates right after creating a value of this type, you might want to consider something like this.
or
Then, you could create an
organizationusingorganization(name: name, address: address)and the coordinates would automatically be set correctly.If neither of these are satisfactory, maybe you should create two different structs to capture the behavior you want.
I would prefer an approach like this, but I like having lots of types.
Finally, as noted in the comments, if you are really just concerned with brevity, you can replace
with
and then replace
with
In fact, you should feel free to combine any of these approaches.
Edit: As pointed out, these solutions do not work as-is. The fundamental tension is trying to work with
CLGeocoder's async method synchronously. One solution is to use a class instead of a struct. The other approach is to use a modification of thewithCoordinatemethod above:This embraces the async nature of
CLGeocoder.Another solution could be to force
CLGeocoderto be synchronous usingDispatchSemaphoreas follows. I don't think these work correctly in Playgrounds, but this should work in an actual app.Here, a new queue to do
Organizationrelated work is created to avoid locking up the main queue. This method creates the least clunky-looking code in my opinion, but probably is not the most performant option. The location APIs are async for a reason.