如何等到 CLGeocoder 完成它的工作

How to wait until CLGeocoder finish its work

我有以下函数根据 GPS 坐标对地址进行地理编码

private func getAddressFromLocation(forLocation: CLLocationCoordinate2D) {
    let geoCoder = CLGeocoder()
    geoCoder.reverseGeocodeLocation(CLLocation(latitude: forLocation.latitude, longitude: forLocation.longitude), completionHandler: {(places, error) in
        guard error == nil else {
            return
        }
        let place: CLPlacemark = places!.first!
        var address: [String] = []
        if place.country != nil { address.append(place.country!) }
        if place.postalCode != nil { address.append(place.postalCode!) }
        if place.locality != nil { address.append(place.locality!) }
        if place.thoroughfare != nil { address.append(place.thoroughfare!) }
        self.fullAddress = address.joined(separator: ",")
    })
}

函数是从我的应用程序的另一部分调用的,我想知道如何确保程序会等到 fullAddress 变量获得值(函数完成)。我试图将函数调用放入同步调度队列,但没有帮助。 感谢您的任何建议。

是的,完成处理程序将成为您的朋友:

typealias CompletionHandler = (_ success:Bool) -> Void

private func getAddressFromLocation(forLocation: CLLocationCoordinate2D, completionHandler: @escaping CompletionHandler) {
    let geoCoder = CLGeocoder()
    geoCoder.reverseGeocodeLocation(CLLocation(latitude: forLocation.latitude, longitude: forLocation.longitude), completionHandler: {(places, error) in
        guard error == nil else {
            completionHandler(false)
            return
        }
        let place: CLPlacemark = places!.first!
        var address: [String] = []
        if place.country != nil { address.append(place.country!) }
        if place.postalCode != nil { address.append(place.postalCode!) }
        if place.locality != nil { address.append(place.locality!) }
        if place.thoroughfare != nil { address.append(place.thoroughfare!) }
        print("address: \(address.joined(separator: ","))")
        completionHandler(true)
    })
}

你可以这样称呼:

getAddressFromLocation(forLocation: CLLocationCoordinate2D()) { success in
    if success {
        //once address is fetched, this will be triggered.
    }
}

我会:

  • 使用 Result 类型的完成处理程序;
  • 将 UI 的更新与反向地理编码分离;
  • 使用Contacts框架中的CNPostalAddressFormatter格式化地址;

例如


enum GeocodeError: Error {
    case notFound
}

let geocoder = CLGeocoder()

func getAddress(for coordinate: CLLocationCoordinate2D, completion: @escaping (Result<String, Error>) -> Void) {
    let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
    geocoder.reverseGeocodeLocation(location) { places, error in
        guard error == nil, let address = places?.first?.postalAddress else {
            completion(.failure(error ?? GeocodeError.notFound))
            return
        }

        let formatter = CNPostalAddressFormatter()
        let string = formatter.string(from: address)
            .components(separatedBy: "\n")
            .joined(separator: ", ")
        completion(.success(string))
    }
}

然后这样称呼它:

getAddress(for: coordinate) { result in
    switch result {
    case .failure(let error):   // update UI to report error, if any
    case .success(let address): // update UI to show address
    }
}