2017-01-29 3 views
0

Я новичок в закрытии в Swift и задавался вопросом, как вернуть мои комментарии из закрытия. Я понимаю, что поскольку он асинхронен, внешний массив не заполняется в нужное время.как мне получить данные из этого закрытия?

Должен ли я использовать что-то вроде обработчика завершения? Как мне это сделать? Какова наилучшая практика для этого? Функция, имеющая обратный вызов, вызывается от didupdateLocation.

fileprivate func getGooglePoisForCurrentLocation(centerLatitude: Double, centerLongitude: Double, delta: Double, count: Int) -> Array<GMAnnotation> 
     { 
      var annotations: [GMAnnotation] = [] 

      placesClient.currentPlace(callback: { (placeLikelihoods, error) -> Void in 
       if let error = error { 
        print("Current Place error: \(error.localizedDescription)") 
        return 
       } 

       if let likelihoodList = placeLikelihoods { 
        for likelihood in likelihoodList.likelihoods { 

         let annotation = GMAnnotation() 
         let place = likelihood.place 

         annotation.location = CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude) 

         annotations.append(annotation) 
        } 


       } 
      }) 

      return annotations; ====> EMPTY 

ответ

3

Да, вам нужно добавить @escaping закрытия вашей функции. Имейте в виду, что асинхронные функции меняют способ работы вашего приложения - например, если вы показываете эти данные в виде таблицы, вам необходимо вызвать tableView.reloadData() (или один из его методов брака), чтобы фактически обновить таблицу после имеются данные. Вот ваша функция закрытия:

fileprivate func getGooglePoisForCurrentLocation(centerLatitude: Double, centerLongitude: Double, delta: Double, count: Int, closure: @escaping (Array<GMAnnotation>) -> Void) { 
    var annotations: [GMAnnotation] = [] 

    placesClient.currentPlace(callback: { (placeLikelihoods, error) -> Void in 
     if let likelihoodList = placeLikelihoods { 
      for likelihood in likelihoodList.likelihoods { 

       let annotation = GMAnnotation() 
       let place = likelihood.place 

       annotation.location = CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude) 

       annotations.append(annotation) 
      } 
      closure(annotations) 
     } 
    }) 
} 

Когда вы называете его, обновить источник данных вашего представления в виде таблицы, а затем перезарядить вид таблицы:

getGooglePoisForCurrentLocationclosure(closure: { (annotations) -> Void in 
    tableViewDataSourceArray = annotations 
    tableView.reloadData() 
}) 

Как примечание стороны, этот пример не особенно безопасный - проверка ошибок отсутствует, а тип возврата не является обязательным. Если вызов API завершится неудачно, он, скорее всего, потерпит крах. Вот более надежная версия той же функции, которая обрабатывает ошибку и правильный тип возврата:

enum PlacesResult { 
    case success(Array<GMAnnotation>) 
    case error(Error) 
} 

fileprivate func getGooglePoisForCurrentLocation(centerLatitude: Double, centerLongitude: Double, delta: Double, count: Int, closure: @escaping (PlacesResult) -> Void) { 
    var annotations: [GMAnnotation] = [] 

    placesClient.currentPlace(callback: { (placeLikelihoods, error) -> Void in 
     if let error = error { 
      print("Current Place error: \(error.localizedDescription)") 
      closure(PlacesResult.error(error)) 
     } 
     if let likelihoodList = placeLikelihoods { 
      for likelihood in likelihoodList.likelihoods { 
       let annotation = GMAnnotation() 
       let place = likelihood.place 
       annotation.location = CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude) 
       annotations.append(annotation) 
      } 
      closure(PlacesResult.success(annotations)) 
     } else { 
      closure(PlacesResult.error(Error())) 
      // something else went wrong but we still want this to call the closure. 
     } 
    }) 
} 
1

Ну, currentPlace вызова асинхронный, поэтому вы не можете немедленно вернуть что-либо в вашей getGooglePoisForCurrentLocation функции.

Вы могли сделать что-то вроде этого, в зависимости от ваших потребностей:

  • магазин аннотаций в частной переменной экземпляра ViewController
  • вызова некоторые обновления UI кода (например, tableView.reloadData или Somthing еще в ваш ViewController) для обновления пользовательского интерфейса. Имейте в виду, что такой вызов должен быть сделано в основном потоке (можно использовать DispatchQueue.main.async сделать это)
Смежные вопросы