使用 MVVM 模式处理 SwiftUI 和 CoreLocation
Handle SwiftUI and CoreLocation with MVVM-Pattern
我正在尝试使用 MVVM-Pattern 实现 SwiftUI 和 CoreLocation。我的 LocationManager
作为助手工作正常。但是如何更改 LocationViewModel
的属性?我在 LocationViewModel
中实施了 LocationManager
的 @ObservedObject
。这是我的问题。
我不知道如何实现它们动态更改的属性。我的 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
}
}
// 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。
但是我怎样才能收到我的 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()
}
}
SwiftUI 2
在这种情况下使用 StateObject
struct LocationView: View {
@StateObject var locationManager: LocationManager = LocationManager()
...
SwiftUI 1
其实LocationViewModel
这里是多余的。由于你的 LocationManager
是一个 ObservableObject
你可以直接在你的视图中使用它,如下所示:
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-Pattern 实现 SwiftUI 和 CoreLocation。我的 LocationManager
作为助手工作正常。但是如何更改 LocationViewModel
的属性?我在 LocationViewModel
中实施了 LocationManager
的 @ObservedObject
。这是我的问题。
我不知道如何实现它们动态更改的属性。我的 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
}
}
// 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。
但是我怎样才能收到我的 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()
}
}
SwiftUI 2
在这种情况下使用 StateObject
struct LocationView: View {
@StateObject var locationManager: LocationManager = LocationManager()
...
SwiftUI 1
其实LocationViewModel
这里是多余的。由于你的 LocationManager
是一个 ObservableObject
你可以直接在你的视图中使用它,如下所示:
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)")
}
}
}