Как правильно дождаться окончания работы функции в swift - PullRequest
1 голос
/ 18 марта 2019

Я уже перепробовал много вещей, но ни одна из них, похоже, не работает.

У меня есть цикл 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)
    }
}

Однако мне никогда не удавалось показать правильное место в ячейке, он всегда показывает пустое пространство, потому что он почему-то не ждет, пока обработчик завершения не завершит преобразование.Что я тут не так делаю?

1 Ответ

2 голосов
/ 18 марта 2019

Это происходит потому, что reverseGeocodeLocation возвращается сразу, а его обработчик завершения запускается позже. Это означает, что значение ret может быть пустым, когда оно помещается в основную очередь. Вы должны отправить на главную из обратного вызова, например:

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