如何正确等待 swift 中的功能完成?
How to properly wait until function has finished doing in swift?
我现在已经尝试了很多方法,但 none 似乎有效。
我有一个 for 循环,它解析一些数据并将坐标转换为 ZIP 字符串:
for i in 0 ... results.count - 1
{
result = results[i]
self.coordinateToString(lat: result.lat, long: result.long, completion: { (place) in
someCell.label.text = place
})
}
func coordinateToString(lat: Double, long: Double, completion: @escaping (String) -> ()) {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: lat, longitude: long)
var ret = ""
geoCoder.reverseGeocodeLocation(location, completionHandler:
{
placemarks, error -> Void in
guard let placeMark = placemarks?.first else { return }
if let zip = placeMark.postalCode, let town = placeMark.subAdministrativeArea
{
let toAppend = "\(zip)" + " \(town)"
ret = toAppend
}
})
DispatchQueue.main.async {
completion(ret)
}
}
但是我从来没有设法在单元格中显示正确的位置,它总是显示为空 space 因为它不知何故不等待完成处理程序完成转换。我在这里做错了什么?
发生这种情况是因为 reverseGeocodeLocation
returns 立即并且其完成处理程序随后运行。这意味着 ret
值在放入主队列时可能为空。您应该从回调中分派到 main,如下所示:
func coordinateToString(lat: Double, long: Double, completion: @escaping (String) -> ()) {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: lat, longitude: long)
var ret = ""
geoCoder.reverseGeocodeLocation(location, completionHandler:
{
placemarks, error -> Void in
guard let placeMark = placemarks?.first else { return }
if let zip = placeMark.postalCode, let town = placeMark.subAdministrativeArea
{
let toAppend = "\(zip)" + " \(town)"
ret = toAppend
DispatchQueue.main.async {
completion(ret)
}
}
})
当然,鉴于这种情况,您需要相应地处理错误情况。更好的是,使用 defer
,这样无论发生什么,都会调用完成:
func coordinateToString(lat: Double, long: Double, completion: @escaping (String) -> ()) {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: lat, longitude: long)
var ret = ""
geoCoder.reverseGeocodeLocation(location, completionHandler:
{
defer {
DispatchQueue.main.async {
completion(ret)
}
}
placemarks, error -> Void in
guard let placeMark = placemarks?.first else { return }
if let zip = placeMark.postalCode, let town = placeMark.subAdministrativeArea
{
let toAppend = "\(zip)" + " \(town)"
ret = toAppend
}
})
我现在已经尝试了很多方法,但 none 似乎有效。
我有一个 for 循环,它解析一些数据并将坐标转换为 ZIP 字符串:
for i in 0 ... results.count - 1
{
result = results[i]
self.coordinateToString(lat: result.lat, long: result.long, completion: { (place) in
someCell.label.text = place
})
}
func coordinateToString(lat: Double, long: Double, completion: @escaping (String) -> ()) {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: lat, longitude: long)
var ret = ""
geoCoder.reverseGeocodeLocation(location, completionHandler:
{
placemarks, error -> Void in
guard let placeMark = placemarks?.first else { return }
if let zip = placeMark.postalCode, let town = placeMark.subAdministrativeArea
{
let toAppend = "\(zip)" + " \(town)"
ret = toAppend
}
})
DispatchQueue.main.async {
completion(ret)
}
}
但是我从来没有设法在单元格中显示正确的位置,它总是显示为空 space 因为它不知何故不等待完成处理程序完成转换。我在这里做错了什么?
发生这种情况是因为 reverseGeocodeLocation
returns 立即并且其完成处理程序随后运行。这意味着 ret
值在放入主队列时可能为空。您应该从回调中分派到 main,如下所示:
func coordinateToString(lat: Double, long: Double, completion: @escaping (String) -> ()) {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: lat, longitude: long)
var ret = ""
geoCoder.reverseGeocodeLocation(location, completionHandler:
{
placemarks, error -> Void in
guard let placeMark = placemarks?.first else { return }
if let zip = placeMark.postalCode, let town = placeMark.subAdministrativeArea
{
let toAppend = "\(zip)" + " \(town)"
ret = toAppend
DispatchQueue.main.async {
completion(ret)
}
}
})
当然,鉴于这种情况,您需要相应地处理错误情况。更好的是,使用 defer
,这样无论发生什么,都会调用完成:
func coordinateToString(lat: Double, long: Double, completion: @escaping (String) -> ()) {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: lat, longitude: long)
var ret = ""
geoCoder.reverseGeocodeLocation(location, completionHandler:
{
defer {
DispatchQueue.main.async {
completion(ret)
}
}
placemarks, error -> Void in
guard let placeMark = placemarks?.first else { return }
if let zip = placeMark.postalCode, let town = placeMark.subAdministrativeArea
{
let toAppend = "\(zip)" + " \(town)"
ret = toAppend
}
})