Home > Mobile >  Swift CLGeocoder to get TimeZone
Swift CLGeocoder to get TimeZone

Time:10-09

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)
        }
  • Related