SwiftUI ObservedObject不更新视图

时间:2020-06-18 22:28:39

标签: ios swift swiftui

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

2 个答案:

答案 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()