This is the function I am calling, which uses the latitude and longitude, converts them into city name and country name, and then returns city name or country name depending on what I want.
import SwiftUI
import CoreLocation
struct junoWeatherEntryView: View {
@ObservedObject var cityVM = allCities()
@State private var searchTerm = "San Francisco"
var body: some View {
VStack{
search
Spacer()
ForEach(cityVM.weather){ item in
Text("\( try await reverseGeocode(lat: item.lat ,lan:item.lan).locality ?? "Unkown")")
}
}
}
func reverseGeocode(lat: Double, lan: Double) async throws -> CLPlacemark {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: lat, longitude: lan) // <- New York
return try await withCheckedThrowingContinuation { continuation in
geoCoder.reverseGeocodeLocation(location) { (placemarks, error) in
guard
error == nil,
let placemark = placemarks?.first
else {
continuation.resume(throwing: error ?? CLError(.geocodeFoundNoResult))
return
}
continuation.resume(returning: placemark)
}
}
}
}
here cityVM is @Published var weather = [WeatherResponse]()
Error i am getting is
1.Cannot pass function of type '(WeatherResponse) async throws -> Text' to parameter expecting synchronous function type
2.Invalid conversion from throwing function of type '(WeatherResponse) async throws -> Text' to non-throwing function type '(Array<WeatherResponse>.Element) -> Text'
I want to show the return value in the TextView how can I achieve this ?
The
reverseGeocodeLocationcalls its completion handler asynchronously (i.e., later). So, there are two common patterns:Use traditional completion handler patterns. E.g.:
And you would call it like so:
Use modern Swift concurrency, e.g.,
And you would call it like so:
Now, in both of those examples, I am returning the entire
CLPlacemark. You could change these to return theStringof justlocalityorcountybased upon yourcityNameBoolean, but the basic idea would be the same. Use completion handler orasyncpattern to handle the return of the asynchronously retrieved information.In your revised question, you ask for an example of how to use this in SwiftUI. You could, for example, use
.task { ... }:And I'd put the business logic in the view model, not the view:
But don't get lost too in the details here, as your example will undoubtedly vary. The idea is to use
.taskto start the asynchronous task, which can update some observable property.