简体   繁体   中英

SwiftUI be notified when all properties of an ObservableObject are updated

I have an ObservableObject


class CurrentPosition: ObservableObject {
    @Published var northEast = CLLocationCoordinate2D()
    @Published var southWest = CLLocationCoordinate2D()


    init(northEast: CLLocationCoordinate2D = CLLocationCoordinate2D(), southWest: CLLocationCoordinate2D = CLLocationCoordinate2D()) {
        self.northEast = northEast
        self.southWest = southWest
    }

    func updateCoordinates(from mapView: MKMapView) {
        self.northEast = mapView.northEastCoordinate
        self.southWest = mapView.southWestCoordinate
    }
}

which I want to update from a MapView

struct MapView: UIViewRepresentable {
    @Binding var weatherStations: [WeatherStation]
    @Binding var selectedWeatherStation: WeatherStation?

    @EnvironmentObject var currentPosition: CurrentPosition

    func makeUIView(context: Context) -> MKMapView {
        let map = MKMapView()
        map.showsUserLocation = true
        map.delegate = context.coordinator
        return map
    }

    func updateUIView(_ uiView: MKMapView, context: Context) {
        updateAnnotations(from: uiView)
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }


    final class Coordinator: NSObject, MKMapViewDelegate {
        var control: MapView

        init(_ control: MapView) {
            self.control = control
        }

        func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
            control.currentPosition.updateCoordinates(from: mapView)
        }

    }
}

and pass it to an AppState object

 MapView(weatherStations: $appState.appData.weatherStations,
                        selectedWeatherStation: $selectedWeatherStation).environmentObject(self.currentPosition)
                    .edgesIgnoringSafeArea(.vertical).onReceive(currentPosition.objectWillChange) { () in
                        self.appState.currentPosition = self.currentPosition
                }}

which in turn passes it to my API client

class AppState: ObservableObject {
    @Published var appData = AppData(weatherStations: [WeatherStation]())
    var currentPosition: CurrentPosition! {
        didSet {
            api.currentPosition = self.currentPosition
        }
    }
}

My issues is that it gets passed each time one of my CurrentPosition properties gets updated, meaning it first gets passed when northEast gets updated, than when southWest gets updated.

How can I pass it only one, when both finished updating?

The easy way is to fold it into one property using a secondary struct , like so:

struct MapCoordinateSpan {
  let northEast: CLLocationCoordinate2D
  let southWest: CLLocationCoordinate2D
}

and revise your CurrentPosition to look like this:

class CurrentPosition: ObservableObject {
    @Published var span: MapCoordinateSpan

    init(northEast: CLLocationCoordinate2D = CLLocationCoordinate2D(), southWest: CLLocationCoordinate2D = CLLocationCoordinate2D()) {
        self.span = MapCoordinateSpan(northEast: northEast, southWest: southWest)
    }

    func updateCoordinates(from mapView: MKMapView) {
        self.span = MapCoordinateSpan(northEast: mapView.northEastCoordinate, southWest: mapView.southWestCoordinate)
    }
}

Then bind to the span property, and pluck out the coordinates from there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM