I'm afraid I likely have the completion handler all messed up. What I am trying to do is use latitude and longitude to get a TimeZone. I want the entire function to return the value with a type TimeZone. The following code works, as in I can get the correct timeZone but it's at the returning stage that it falls apart.
func getTimeZone(location: CLLocationCoordinate2D, completion: () -> TimeZone) -> TimeZone {
var timeZone = TimeZone(identifier: "timeZone")
var placemark: CLPlacemark?
let cllLocation = CLLocation(latitude: location.latitude, longitude: location.longitude)
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(cllLocation) { placemarks, error in
if let error = error {
print(error.localizedDescription)
} else {
if let placemarks = placemarks {
placemark = placemarks.first
}
}
DispatchQueue.main.async {
if let optTime = placemark?.timeZone {
timeZone = optTime
}
return completion()
}
}
}
CodePudding user response:
I think there is a problem with the completion implementation. Try to change it to something like this:
func getTimeZone(location: CLLocationCoordinate2D, completion: @escaping ((TimeZone) -> Void)) {
let cllLocation = CLLocation(latitude: location.latitude, longitude: location.longitude)
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(cllLocation) { placemarks, error in
if let error = error {
print(error.localizedDescription)
} else {
if let placemarks = placemarks {
if let optTime = placemarks.first!.timeZone {
completion(optTime)
}
}
}
}
}
Then you can call the function like this:
getTimeZone(location: CLLocationCoordinate2D(latitude: CLLocationDegrees(9.62), longitude: CLLocationDegrees(84.62))) { timeZone in
print("Time zone: \(timeZone)")
}
CodePudding user response:
You've got it almost right. Get rid of the return value. You can't return a function result from an async function like that.
Instead the caller passes in a completion handler that executes when the result is returned:
func getTimeZone(location: CLLocationCoordinate2D, completion: @escaping (TimeZone) -> ()) {
var timeZone = TimeZone(identifier: "timeZone")
var placemark: CLPlacemark?
let cllLocation = CLLocation(latitude: location.latitude, longitude: location.longitude)
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(cllLocation) { placemarks, error in
if let error = error {
print(error.localizedDescription)
} else {
if let placemarks = placemarks {
placemark = placemarks.first
}
}
DispatchQueue.main.async {
if let optTime = placemark?.timeZone {
timeZone = optTime
}
completion(timeZone)
}
}
}
Then, to use it:
getTimeZone(location: someLocation) { timeZone in
// This code will execute once the time zone is calculated.
print("The time zone for that location is \(timeZone.description)")
}
CodePudding user response:
Why are you trying to return a value when you have async reverseGeocodeLocation
involved in getTimeZone
func getTimeZone(location: CLLocationCoordinate2D, completion: @escaping (TimeZone) -> ()) {
var placemark: CLPlacemark?
let cllLocation = CLLocation(latitude: location.latitude, longitude: location.longitude)
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(cllLocation) { placemarks, error in
if let error = error {
print(error.localizedDescription)
} else {
if let placemarks = placemarks {
placemark = placemarks.first
}
}
DispatchQueue.main.async {
if let optTime = placemark?.timeZone {
completion(optTime)
}
}
}
}
Finally use it as
getTimeZone(location: your_location_coordinates_here) {[weak self] timeZone in
debugPrint(timeZone)
}