使用MVVM模式处理SwiftUI和CoreLocation [英] Handle SwiftUI and CoreLocation with MVVM-Pattern

查看:472
本文介绍了使用MVVM模式处理SwiftUI和CoreLocation的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 MVVM模式实现 SwiftUI CoreLocation 。我的 LocationManager 作为助手可以正常工作。但是,如何更改 LocationViewModel 的属性?我在 LocationViewModel 中实现了 LocationManager @ObservedObject 。这是我的问题。

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.

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

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()
    }
}

更新

现在,我已经设置了 MapView

Now, I have set up my MapView.

但是如何接收 LocationManager 的数据? didUpdateLocations 方法在 LocationManager 中有效。

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

我试图做的所有事情都出错了。我想根据当前用户位置在 MapView 上设置区域。在UIKit中,它非常简单,但是在SwiftUI中,它却很怪异。

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()
    }
}


推荐答案

SwiftUI 2

在此使用 StateObject 代替case

Use instead StateObject in this case

struct LocationView: View {

    @StateObject var locationManager: LocationManager = LocationManager()
    ...

SwiftUI 1

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

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)")
        }
    }
}

这篇关于使用MVVM模式处理SwiftUI和CoreLocation的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆