Swift CLGeocoder获取时区



恐怕我可能把完成处理程序弄乱了。我要做的是使用纬度和经度来获得一个时区。我希望整个函数返回TimeZone类型的值。下面的代码可以工作,因为我可以获得正确的时区,但在返回阶段它崩溃了。

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()
}
}
}

我认为完成实现有问题。试着把它改成这样:

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

然后你可以像这样调用这个函数:

getTimeZone(location: CLLocationCoordinate2D(latitude: CLLocationDegrees(9.62), longitude: CLLocationDegrees(84.62))) { timeZone in
print("Time zone: (timeZone)")
}

你几乎答对了。去掉返回值。你不能像这样从异步函数返回函数结果。

调用者传递一个完成处理程序,该处理程序在返回结果时执行:

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

然后,使用它:

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)")
}

当您在getTimeZone中涉及异步reverseGeocodeLocation时,为什么要尝试返回值

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

最后使用

getTimeZone(location: your_location_coordinates_here) {[weak self] timeZone in
debugPrint(timeZone)
}

Xcode 14日,斯威夫特5.7

CLLocationCoordinate2D在Xcode 14中导致问题。如果你在一个新的playground或Xcode 14项目中运行以下代码:

import CoreLocation
print("Before")
let center = CLLocationCoordinate2D()
print("After")

这将立即崩溃游乐场或停止您的代码由于这个错误:

libc++abi: terminating with uncaught exception of type NSException

我有一个例子,这工作在Xcode 14.0 SwiftUI项目和Playground使用CLLocation而不是CLLocationCoordinate2D:

import CoreLocation
func getTimeZone(location: CLLocation, completion: @escaping ((TimeZone) -> Void)) {

let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) in
if error != nil {
print("reverse geodcode fail: (String(describing: error))")
} else if let placemarks = placemarks, let pm = placemarks.first {

if let val = pm.timeZone {
completion(val)
}
}
})
}
getTimeZone(location: CLLocation(latitude: 42.48001070918, longitude: -76.4511703657)) { timeZone in
print("My Time zone: (timeZone.identifier)")
}

输出:My Time zone: America/New_York

这是一个变化(基于对这篇文章的修改答案:运行reverseGeocodeLocation函数,在SwiftPlay中创建异常或不返回任何东西),如果你想使用字符串查找纬度和经度,并从位置返回所有其他信息:

import CoreLocation
func getAddressFromLatLon(pdblLatitude: String, withLongitude pdblLongitude: String) {
guard let lat = Double(pdblLatitude),
let lon = Double(pdblLongitude) else { return }
let loc = CLLocation(latitude: lat, longitude: lon)
let ceo = CLGeocoder()
ceo.reverseGeocodeLocation(loc, completionHandler: { (placemarks, error) in
if error != nil {
print("reverse geodcode fail: (String(describing: error))")
} else if let placemarks = placemarks, let pm = placemarks.first {
var addressString = ""
if let val = pm.subLocality {
addressString += val + ", "
}
if let val = pm.thoroughfare {
addressString += val + ", "
}
if let val = pm.locality {
addressString += val + ", "
}
if let val = pm.country {
addressString += val + ", "
}
if let val = pm.postalCode {
addressString += val + " "
}
print(addressString)
}
})
}
getAddressFromLatLon(pdblLatitude: "42.48001070918", withLongitude: "-76.4511703657")

输出:Sapsucker Woods Rd, Lansing, United States, 14850

最新更新