Swift:用于地理编码的递归异步循环

Swift: Asynchronous Loop with Recursion for GeoCoding

一次只能发生一个 GeoCode 请求,而且它们是异步的,所以我需要在前一个完成后立即开始下一个。我让它像这样工作:

func one() {
        let geocoder = CLGeocoder()
        let one = myPlacesFakeData[0]

        geocoder.geocodeAddressString(one.address, completionHandler: { (placemarks, error) in
            if let error = error {
                print("Unable to Reverse Geocode Location (\(error))")
            } else {
                if let placemarks = placemarks, let placemark = placemarks.first {
                    myPlacesFakeData[0].latitude = placemark.location?.coordinate.latitude
                    myPlacesFakeData[0].longitude = placemark.location?.coordinate.longitude
                } else {
                    print("No Matching Address Found")
                }
            }

            self.two()
        })
    }

    func two() {
        let geocoder = CLGeocoder()
        let two = myPlacesFakeData[1]

        geocoder.geocodeAddressString(two.address, completionHandler: { (placemarks, error) in
            if let error = error {
                print("Unable to Reverse Geocode Location (\(error))")
            } else {
                if let placemarks = placemarks, let placemark = placemarks.first {
                    myPlacesFakeData[1].latitude = placemark.location?.coordinate.latitude
                    myPlacesFakeData[1].longitude = placemark.location?.coordinate.longitude
                } else {
                    print("No Matching Address Found")
                }
            }
            self.three()
        })
    }

    func three() {
        let geocoder = CLGeocoder()
        let three = myPlacesFakeData[2]

        geocoder.geocodeAddressString(three.address, completionHandler: { (placemarks, error) in
            if let error = error {
                print("Unable to Reverse Geocode Location (\(error))")
            } else {
                if let placemarks = placemarks, let placemark = placemarks.first {
                    myPlacesFakeData[2].latitude = placemark.location?.coordinate.latitude
                    myPlacesFakeData[2].longitude = placemark.location?.coordinate.longitude
                } else {
                    print("No Matching Address Found")
                }
            }

        })
    }

但这是贫民窟,取决于我尝试地理编码的恰好三个地方。

我想我需要一个递归函数和一个计数器,但我不确定如何写这个。任何帮助将不胜感激。

这是展示一种方法的游乐场。您可以使用一个函数,该函数将调用自身并累积结果,一旦所有地址都经过地理编码,该函数最终将调用完成处理程序。您可以通过错误处理和更好的类型包装来做得更好,但这是一个很好的起点!

//: Playground - noun: a place where people can play

import Cocoa
import CoreLocation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

func geoCode(addresses: [String], results: [CLPlacemark] = [], completion: @escaping ([CLPlacemark]) -> Void ) {
    guard let address = addresses.first else {
        completion(results)
        return
    }

    let geoCoder = CLGeocoder()
    geoCoder.geocodeAddressString(address) { placemarks, error in

        var updatedResults = results

        if let placemark = placemarks?.first {
            updatedResults.append(placemark)
        }

        let remainingAddresses = Array(addresses[1..<addresses.count])

        geoCode(addresses: remainingAddresses, results: updatedResults, completion: completion)
    }
}

let addresses = ["1600 Pennsylvania Ave NW, Washington, DC 20500", "1 Infinite Loop, Cupertino, CA"]

geoCode(addresses: addresses) { results in
    print("Got back \(results.count) results")
}