我有一个显示用户名的视图。 ClientViewModel
具有方法loadClient()
,该方法采用Firestore文档参考,加载用户并更新模型,后者应更新视图。但是视图没有被更新。在loadClient()
中,displayName
的打印正确,然后我更新了模型,但是视图没有更新。我究竟做错了什么?
struct ItemView: View {
@EnvironmentObject var sessionStore: SessionStore
@ObservedObject var itemViewModel: ItemViewModel
@ObservedObject var clientViewModel = ClientViewModel()
func onAppear() {
itemViewModel.calcRoute() // this makes my client model null.
clientViewModel.loadClient(documentReference: itemViewModel.item.ownerReference)
}
var body: some View {
LoadingView(isShowing: $itemViewModel.isAnimating) {
VStack {
ItemDetailsView(itemViewModel: self.itemViewModel, clientViewModel: self.clientViewModel)
}
.navigationBarItems(trailing: EditButtonView(item: self.itemViewModel.item))
.onAppear(perform: self.onAppear)
}
}
}
struct ItemDetailsView: View {
@ObservedObject var itemViewModel: ItemViewModel
@ObservedObject var clientViewModel = ClientViewModel()
var body: some View {
Text(clientViewModel.client?.displayName ?? "nope")
.onAppear() {
self.clientViewModel.loadClient(documentReference: self.itemViewModel.item.ownerReference)
}
}
}
class ClientViewModel: ObservableObject {
@Published var client: Client?
@Published var error = ""
var firestoreService: FirestoreService = FirestoreService()
func loadClient(documentReference: DocumentReference) {
documentReference.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
self.error = error!.localizedDescription
return
}
guard let data = document.data() else {
print("Document data was empty.")
return
}
self.client = Client(document: document)
print(self.client?.displayName) // this prints the name
}
}
}
class ItemViewModel: ObservableObject {
var firestoreService = FirestoreService()
@Published var item: Item
@Published var distance: String = "0 km"
@Published var travelTime = ""
@Published var route: MKRoute?
@Published var price: String = ""
@Published var error: String = ""
@Published var isAnimating: Bool = true
init(item: Item) {
self.item = item
}
// kte n servis
func calcRoute() {
let sourcePlacemark = MKPlacemark(coordinate: CLLocationCoordinate2D(
latitude: item.location.coordinate.latitude,
longitude: item.location.coordinate.longitude
))
let destinationPlacemark = MKPlacemark(coordinate: CLLocationCoordinate2D(
latitude: item.destination.coordinate.latitude,
longitude: item.destination.coordinate.longitude
))
let directionRequest = MKDirections.Request()
directionRequest.source = MKMapItem(placemark: sourcePlacemark)
directionRequest.destination = MKMapItem(placemark: destinationPlacemark)
directionRequest.transportType = .automobile
let directions = MKDirections(request: directionRequest)
directions.calculate { (response, error) in
self.isAnimating = false
guard let directionResponse = response else {
if let error = error {
self.error = error.localizedDescription
}
return
}
let route = directionResponse.routes[0]
self.route = route
self.travelTime = route.expectedTravelTime.asString(style: .abbreviated)
self.distance = "\((route.distance / 1000).rounded()) km"
let price = route.distance / 1000 //km
self.price = "\(price / 10)"
}
}
}
答案 0 :(得分:1)
必须在主队列上更新所有@Published
属性,才能更新UI。这是更正的变体
func loadClient(documentReference: DocumentReference) {
documentReference.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
DispatchQueue.main.async { // << here !!
self.error = error!.localizedDescription
}
return
}
guard let data = document.data() else {
print("Document data was empty.")
return
}
DispatchQueue.main.async { // << here !!
self.client = Client(document: document)
print(self.client?.displayName) // this prints the name
}
}
}
答案 1 :(得分:0)
使用@StateObject
代替ObservedObject
解决了。
@StateObject var clientViewModel = ClientViewModel()