Handle SwiftUI and CoreLocation with MVVM-Pattern

心不动则不痛 提交于 2020-02-22 05:39:28

问题


i am trying to implement SwiftUI and CoreLocation with the MVVM-Pattern. My LocationManager as Helper works fine. But how I can change the properties of my LocationViewModel? I am implemented my @ObservedObject of the LocationManager in LocationViewModel. Here is my problem.

I don't have a idea to implement properties they change on the fly. Nothing is changed in my LocationView. By pressing a Button anything works fine one time. But the LocationViewModel must change there properties on every change of the LocationManager.

In summary I would like to display the current user position.

// Location Manager as Helper

import Foundation
import CoreLocation

class LocationManager: NSObject, ObservableObject {

    let locationManager = CLLocationManager()
    let geoCoder = CLGeocoder()

    @Published var location: CLLocation?
    @Published var placemark: CLPlacemark?

    override init() {
        super.init()
        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
    }

    func geoCode(with location: CLLocation) {

        geoCoder.reverseGeocodeLocation(location) { (placemark, error) in
            if error != nil {
                print(error!.localizedDescription)
            } else {
                self.placemark = placemark?.first
            }
        }
    }
}

extension LocationManager: CLLocationManagerDelegate {

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.first else { return }

        DispatchQueue.main.async {
            self.location = location
            self.geoCode(with: location)
        }

    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        // TODO
    }
}

// Location Model

import Foundation
import CoreLocation

struct Location {
    var location: CLLocation = CLLocation()
    var placemark: CLPlacemark = CLPlacemark()
}
// Location View Model

import SwiftUI
import CoreLocation

class LocationViewModel: ObservableObject {

    @ObservedObject var locationManager: LocationManager = LocationManager()

    @Published var location: Location

    init() {
        self.location = Location()
    }
}
// Location View

import SwiftUI

struct LocationView: View {

    @ObservedObject var locationViewModel: LocationViewModel = LocationViewModel()

    var body: some View {
        VStack(alignment: .leading) {
            Text("Latitude: \(self.locationViewModel.location.location.coordinate.latitude.description)")
            Text("Longitude: \(self.locationViewModel.location.location.coordinate.longitude.description)")
        }
    }
}

struct LocationView_Previews: PreviewProvider {
    static var previews: some View {
        LocationView()
    }
}

Update

Now, I have set up my MapView.

But how I can receive the data of my LocationManager? The didUpdateLocations method is working in LocationManager.

All what I am trying to do goes wrong. I would like to set the region on my MapView based on the current user location. In UIKit it was very simple, but in SwiftUI it is freaky.

// Map View

import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {

    @ObservedObject var locationManager: LocationManager = LocationManager()

    class Coordinator: NSObject, MKMapViewDelegate {

        var parent: MapView

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

    }

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

    func makeUIView(context: Context) -> MKMapView {
        let mapView = MKMapView(frame: .zero)
        mapView.delegate = context.coordinator
        return mapView
    }

    func updateUIView(_ mapView: MKMapView, context: Context) {
        mapView.showsUserLocation = true
    }

}

struct MapView_Previews: PreviewProvider {
    static var previews: some View {
        MapView()
    }
}

回答1:


Actually LocationViewModel is redundant here. As your LocationManager is a ObservableObject you can use it directly in your view, as below:

struct LocationView: View {

    @ObservedObject var locationManager: LocationManager = LocationManager()

    var body: some View {
        VStack(alignment: .leading) {
            Text("Latitude: \(locationManager.location.coordinate.latitude.description)")
            Text("Longitude: \(locationManager.location.coordinate.longitude.description)")
        }
    }
}


来源:https://stackoverflow.com/questions/59620573/handle-swiftui-and-corelocation-with-mvvm-pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!