使用 MVVM 模式处理 SwiftUI 和 CoreLocation

Jur*_*rie 5 xcode mvvm core-location swift swiftui

我正在尝试使用MVVM-Pattern实现SwiftUICoreLocation。我的助手工作正常。但我怎样才能改变我的属性呢?我已经实现了我的. 这是我的问题。LocationManagerLocationViewModel@ObservedObjectLocationManagerLocationViewModel

我不知道如何实现它们动态更改的属性。我的 LocationView 中没有任何变化。通过按下一个按钮,任何事情一次都能正常工作。但LocationViewModel每次更改时都必须更改这些属性LocationManager

总之,我想显示当前用户的位置。

// 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
    }
}

Run Code Online (Sandbox Code Playgroud)
// Location Model

import Foundation
import CoreLocation

struct Location {
    var location: CLLocation = CLLocation()
    var placemark: CLPlacemark = CLPlacemark()
}
Run Code Online (Sandbox Code Playgroud)
// Location View Model

import SwiftUI
import CoreLocation

class LocationViewModel: ObservableObject {

    @ObservedObject var locationManager: LocationManager = LocationManager()

    @Published var location: Location

    init() {
        self.location = Location()
    }
}
Run Code Online (Sandbox Code Playgroud)
// 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()
    }
}
Run Code Online (Sandbox Code Playgroud)

更新

现在,我已经设置了我的MapView

但我怎样才能收到我的数据LocationManager呢?该didUpdateLocations方法正在运行LocationManager

我想做的一切都出错了。MapView我想根据当前用户位置设置区域。在 UIKit 中它非常简单,但在 SwiftUI 中却很奇怪。

// 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()
    }
}
Run Code Online (Sandbox Code Playgroud)

Asp*_*eri 1

SwiftUI 2

StateObject在这种情况下使用

struct LocationView: View {

    @StateObject var locationManager: LocationManager = LocationManager()
    ...
Run Code Online (Sandbox Code Playgroud)

SwiftUI 1

其实LocationViewModel这里是多余的。由于您LocationManager是 aObservableObject您可以直接在您的视图中使用它,如下所示:

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)")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,效果很好。这个实现符合MVVM模式吗?我正在尝试理解 SwiftUI 的这种模式。然而,在这种情况下,它并不容易使用。 (2认同)