Ios SwiftUI ObservedObject未更新视图

Ios SwiftUI ObservedObject未更新视图,ios,swift,swiftui,Ios,Swift,Swiftui,我有一个显示用户名的视图ClientViewModel有一个方法loadClient(),该方法获取Firestore文档引用,加载用户并更新模型,该模型应更新视图。但是视图没有被更新。在loadClient()中,正确打印了displayName,然后我更新了模型,但没有更新视图。我做错了什么 struct ItemView: View { @EnvironmentObject var sessionStore: SessionStore @ObservedObject var

我有一个显示用户名的视图
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)"
        }
    }
}

必须更新主队列上所有已发布的属性,才能更新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
            }
        }
    }
func加载客户端(documentReference:documentReference){
documentReference.addSnapshotListener{documentSnapshot,出现错误
guard let document=documentSnapshot else{

DispatchQueue.main.async{/通过使用
@StateObject
而不是
ObservedObject
解决

@StateObject var clientViewModel = ClientViewModel()

当我删除所有与firebase相关的代码时,它按预期工作。但是为什么我要在方法中正确打印名称?将客户端属性的更新发送到主队列不工作,名称仍然没有显示在视图中。不工作,名称仍然没有显示在视图中。确定我找到了哪一行正在断开它。在我的ItemView(ItemDetailsView的父级)中,onAppear()正在运行这个calcRoute()方法。如果我对它进行注释,它会工作,当我进行更近距离的拍摄时,首先显示名称,然后在calcRoute完成后,它会变为零。