Как вызвать функцию после нескольких асинхронных API-запросов fini sh в SwiftUI? - PullRequest
0 голосов
/ 05 января 2020

Я все еще развиваю свои навыки в SwiftUI, так что спасибо всем опытным разработчикам, которые могут помочь ответить на мой вопрос.

Для контекста я создаю приложение, которое отображает маркеры на карте, а также список маркеров также. Я использую @EnvironmentObject для хранения данных, чтобы был «один источник правды» и чтобы карта и список автоматически обновлялись при изменении данных.

Чтобы получить нужные мне данные, я делаю 2 типа: API-запросы. Один, чтобы получить список местоположений, затем для каждого местоположения я делаю запрос на дополнительную информацию о каждом соответствующем местоположении.

Чтобы обновить установленный мной @EnvironmentObject, мне нужно выполнить все запросы, а затем обновить его из основного потока приложения. Поэтому моя проблема заключается в том, что мне нужно иметь возможность вызывать функцию только после того, как API-запросы завершат Я надеюсь, что кто-то может показать мне, как изменить их, чтобы я мог вызвать функцию после выполнения 2 запросов:


Вот скелет моего файла, который отображает карту и где я делаю мои запросы API: Основная часть находится в 'расширение GMController' внизу

import SwiftUI
import UIKit
import GoogleMaps
import GooglePlaces
import CoreLocation
import Foundation



struct GoogMapView: View {
    var body: some View {
        GoogMapControllerRepresentable()
    }
}



class GoogMapController: UIViewController, CLLocationManagerDelegate {
    var locationManager = CLLocationManager()
    var mapView: GMSMapView!
    let defaultLocation = CLLocation(latitude: 42.361145, longitude: -71.057083)
    var zoomLevel: Float = 15.0
    let marker : GMSMarker = GMSMarker()


    override func viewDidLoad() {
        super.viewDidLoad()

        locationManager = CLLocationManager()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestAlwaysAuthorization()
        locationManager.distanceFilter = 50
        locationManager.startUpdatingLocation()
        locationManager.delegate = self

        let camera = GMSCameraPosition.camera(withLatitude: defaultLocation.coordinate.latitude, longitude: defaultLocation.coordinate.longitude, zoom: zoomLevel)
        mapView = GMSMapView.map(withFrame: view.bounds, camera: camera)
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        mapView.setMinZoom(14, maxZoom: 20)
        mapView.settings.compassButton = true
        mapView.isMyLocationEnabled = true
        mapView.settings.myLocationButton = true
        mapView.settings.scrollGestures = true
        mapView.settings.zoomGestures = true
        mapView.settings.rotateGestures = true
        mapView.settings.tiltGestures = true
        mapView.isIndoorEnabled = false


        marker.position = CLLocationCoordinate2D(latitude: 42.361145, longitude: -71.057083)
        marker.title = "Boston"
        marker.snippet = "USA"
        marker.map = mapView

        view.addSubview(mapView)

    }

    // Handle incoming location events.
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
      let location: CLLocation = locations.last!
      print("Location: \(location)")

      let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude, longitude: location.coordinate.longitude, zoom: zoomLevel)


        mapView.animate(to: camera)

    }

    // Handle authorization for the location manager.
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
      switch status {
      case .restricted:
        print("Location access was restricted.")
      case .denied:
        print("User denied access to location.")
        // Display the map using the default location.
        mapView.isHidden = false
      case .notDetermined:
        print("Location status not determined.")
      case .authorizedAlways: fallthrough
      case .authorizedWhenInUse:
        print("Location status is OK.")
      }
    }

    // Handle location manager errors.
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
      locationManager.stopUpdatingLocation()
      print("Error: \(error)")
    }

}


// UIViewControllerExtension
extension GMController {


    func requestAndCombineGData(location: CLLocation, radius: Int) {
    // Clears map of markers
        self.mapView.clear()

    // vvv  THIS IS WHERE I AM TRYING TO CALL THE REQUESTS IN SUCCESSION AND THEN CALL A FUNCTION AFTER THE REQUESTS ARE FINISHED  vvv
        // Calls 'Nearby Search' request
        googleClient.getGooglePlacesData(location: location, withinMeters: radius) { (response) in
            print("Made Nearby Search request. Returned response here:", response)

            // loops through each result from the above Nearby Request' to get the 'place_id' and make 'Place Details'
            for location in response.results {
                // Calls 'Place Details' request
                self.googleClient.getGooglePlacesDetailsData(place_id: location.place_id) { (detailsResponse) in
                    print("GMV returned - detailsResponse.result - ", detailsResponse.result)

                }
            }            
        }

    }

}



struct GoogMapControllerRepresentable: UIViewControllerRepresentable {
    func makeUIViewController(context: UIViewControllerRepresentableContext<GMControllerRepresentable>) -> GMController {
        return GMController()
    }

    func updateUIViewController(_ uiViewController: GMController, context: UIViewControllerRepresentableContext<GMControllerRepresentable>) {

    }
}



Кто-нибудь знает, как я могу изменить свой код, чтобы я мог вызывать функцию только после выполнения всех запросов API, которая может использовать данные из запросов?

1 Ответ

1 голос
/ 06 января 2020

Предполагается, что вы вызываете второй вызов API с первого или по окончании первого вызова API.

Добавьте наблюдателя в свой viewDidLoad ()

NotificationCenter.default.addObserver(self, selector: #selector(
self.methodOfReceivedNotification(notification:)), name: Notification.Name
("NotificationIdentifier"), object: nil)

затем добавьте почтовое уведомление о вызове API 'location', когда дело удовлетворено, или когда условие выполнено, или когда вызов завершен

NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"),
object: nil)

Затем внутри этого напишите все, что вы хочу произойти после завершения вызова местоположения.

@objc func methodOfReceivedNotification(notification: Notification) 
{
///
}
...