I have some code that generates map coordinates and reverse geolocation when an entry save button is clicked. The button click calls the function saveButton() and in turn getLocation(). The print statement at the bottom of getLocation() is correctly displaying the formatted address but is not making it back up to saveButton() where the address is saved to core data and prints the newEntry.address (nothing is displayed). I am not getting any errors or warnings so I am wondering if there is a problem with an optional.
So in summary, reverse geoLocation is working, it just isn't getting stored in core data.
The code below mainly shows only snippets related to location coordinates and address.
struct EntryView: View {
@Environment(\.managedObjectContext) var viewContext // core data
@ObservedObject private var lm = LocationManager() // location
@State private var entryLat: Double = 0.0
@State private var entryLong: Double = 0.0
@State private var addr: String = ""
var body: some View {
GeometryReader { g in
List {
Button(action: {
self.saveButton() // save entry button pressed
}) {
HStack {
Spacer()
Text ("Save")
Spacer()
}
}
}
.navigationBarHidden(true)
.navigationViewStyle(StackNavigationViewStyle())
}
// the save button has been pressed
func saveButton() {
// get coordinates and address
let addr = getLocation()
print("addr = \(addr)") // nothing displayed here except addr
// save entry to core data
let newEntry = CurrTrans(context: viewContext)
newEntry.id = UUID()
newEntry.entryDT = entryDT // entry date
newEntry.entryDsc = entryDsc // entry description
newEntry.moneyD = moneyD // money as double
newEntry.entryLat = entryLat // store location for maps
newEntry.entryLong = entryLong
newEntry.address = addr // formatted address
print("newEntry.address = \(newEntry.address ?? "")")
do {
try viewContext.save()
} catch {
print(error.localizedDescription)
}
}
func getLocation() -> String {
// get transaction location coordinates
let result = lm.getLocationCoordinates()
entryLat = result.0
entryLong = result.1
// get location address
let location = CLLocation(latitude: entryLat, longitude: entryLong)
location.placemark { placemark, error in
guard let placemark = placemark else {
print("Error:", error ?? "nil")
return
}
print("formatted address: \(placemark.postalAddressFormatted ?? "")")
addr = placemark.postalAddressFormatted ?? "Unknown"
return addr
}
}
}
The code below is part of the location manager.
extension CLLocation {
func placemark(completion: @escaping (_ placemark: CLPlacemark?, _ error: Error?) -> ()) {
CLGeocoder().reverseGeocodeLocation(self) { completion($0?.first, $1) }
}
}
extension CLPlacemark {
/// street name, eg. Infinite Loop
var streetName: String? { thoroughfare }
/// // eg. 1
var streetNumber: String? { subThoroughfare }
/// city, eg. Cupertino
var city: String? { locality }
/// neighborhood, common name, eg. Mission District
var neighborhood: String? { subLocality }
/// state, eg. CA
var state: String? { administrativeArea }
/// county, eg. Santa Clara
var county: String? { subAdministrativeArea }
/// zip code, eg. 95014
var zipCode: String? { postalCode }
/// postal address formatted
var postalAddressFormatted: String? {
guard let postalAddress = postalAddress else { return nil }
return CNPostalAddressFormatter().string(from: postalAddress)
}
}