【问题标题】:SwiftUI: Updating Firestore from DetailViewSwiftUI:从 DetailView 更新 Firestore
【发布时间】:2021-05-15 12:31:01
【问题描述】:

我正在努力将 Firestore 存储库整合到 SwiftUI 2 应用程序中。列表视图会适当加载,并在 Firestore 集合中的数据发生更改时自动刷新。 NavigationLink 正确加载适当的 DetailView。 DetailView 上的一个按钮设置为更改相关文档内的数据,并且可以正常工作,但是 DetailView 页面没有刷新正确的数据(退出到列表视图并返回时正确显示);同样,DetailView 不会响应对其他地方的集合所做的更改。

我尝试使用 ObservedObject 和 State 的各种配置,但无法获得预期的结果。

任何帮助将不胜感激。下面列出的 Snipped Code 显示了流程,并以状态字段为例。

客户存储库

class CustomerRepository: ObservableObject {
    
    private let path: String = "customers"
    private let store = Firestore.firestore()
    @Published var customers: [Customer] = []
    
    private var cancellables: Set<AnyCancellable> = []
    
    init() {
        store.collection(path)
            .addSnapshotListener { querySnapshot, error in
                if let error = error {
                    print("Error getting customers \(error.localizedDescription)")
                    return
                }
                
                self.customers = querySnapshot?.documents.compactMap { document in
                    
                    try? document.data(as: Customer.self)
                    
                } ?? []
            }
    }
    
    func update(_ customer: Customer) {
        guard let customerID = customer.id else { return }
        
        do {
            try store.collection(path).document(customerID).setData(from: customer)
        } catch {
            fatalError("Unable to update record: \(error.localizedDescription)")
        }
    }
}

客户列表视图模型

class CustomerListViewModel: ObservableObject {
    
    @Published var customerViewModels: [CustomerViewModel] = []
    
    private var cancellables: Set<AnyCancellable> = []
    
    @Published var customerRepository = CustomerRepository()
    
    init() {
        customerRepository.$customers.map { customers in
            customers.map(CustomerViewModel.init)
        }
        .assign(to: \.customerViewModels, on: self)
        
        .store(in: &cancellables)
    }
}

客户视图模型

class CustomerViewModel: ObservableObject, Identifiable {
    
    private let customerRepository = CustomerRepository()
    
    @Published var customer: Customer
    
    private var cancellables: Set<AnyCancellable> = []
    
    var id = ""
    
    init(customer: Customer) {
        self.customer = customer
        
        $customer
            .compactMap { $0.id }
            .assign(to: \.id, on: self)
            .store(in: &cancellables)
    }
    
    func update(customer: Customer) {
        customerRepository.update(customer)
    }
}

客户列表视图

struct CustomerListView: View {
    
    @ObservedObject var customerListViewModel = CustomerListViewModel()

    var body: some View {
        NavigationView {
            List {
                ForEach(customerListViewModel.customerViewModels) { customerViewModel in
                    
                    NavigationLink(
                        destination: CustomerDetailView(customerViewModel: customerViewModel)) {
                            CustomerCell(customerViewModel: customerViewModel)
                        }
                }
            }
        }
    }
}

客户详情视图

struct CustomerDetailView: View {
    var customerViewModel: CustomerViewModel
    
    var body: some View {
        VStack {
            
            Text(customerViewModel.customer.status.description)
            
        }.onTapGesture {
                    nextTask()
                }
    }

private func nextTask() {
        switch customerViewModel.customer.status {
        case .dispatched:
            customerViewModel.customer.status = .accepted
        
...

        default:
            return
        }
        
        update(customer: customerViewModel.customer)
        
    }
    
    func update(customer: Customer) {
        customerViewModel.update(customer: customer)
    }
}

【问题讨论】:

  • 我在这里有类似的问题stackoverflow.com/questions/66141387/…
  • 谢谢。我查看了您收到的两个建议,但似乎都没有解决我的问题。但如果我得到解决方案,我会将您的问题添加为书签。

标签: firebase google-cloud-firestore swiftui


【解决方案1】:

经过一些重新配置,以及这个例子的帮助:

https://peterfriese.dev/swiftui-firebase-update-data/

我能够解决我的问题。下面是修改后的代码的细分,以防它对其他人有所帮助....

客户视图模型

class CustomerViewModel: ObservableObject, Identifiable {
    
    @Published var customer: Customer
    @Published var modified = false
    
    private var cancellables: Set<AnyCancellable> = []
    
    init(customer: Customer = Customer(status: .new)) {
        self.customer = customer
        
        self.$customer
            .dropFirst()
            .sing { [weak self] customer in
               self?.modified = true
            }
            .store(in: &cancellables)
    }
    
    func handleDoneTapped() {
      self.updateOrAddCustomer()
  }
}

客户列表视图

// Snip to Navigation Link

    NavigationLink(
        destination: CustomerDetailView(customerViewModel: CustomerViewModel(customer: customerViewModel.customer))) {
                            CustomerCell(customerViewModel: customerViewModel)
                        }

客户详情视图

struct CustomerDetailView: View {
    @ObservedObject var customerViewModel = CustomerViewModel()
    
    var body: some View {
        VStack {
            
            Text(customerViewModel.customer.status.description)
            
        }.onTapGesture {
                    nextTask()
                }
    }

private func nextTask() {
        switch customerViewModel.customer.status {
        case .dispatched:
            customerViewModel.customer.status = .accepted
        
...

        default:
            return
        }
        
        update(customer: customerViewModel.customer)
        
    }
    
    func update(customer: Customer) {
        customerViewModel.handleDoneTapped()
    }
}

【讨论】:

    【解决方案2】:

    您需要在此处放置要更新值的参数,并希望 UI 相应地更新:

    class CustomerViewModel: ObservableObject, Identifiable {
        
        private let customerRepository = CustomerRepository()
        
        @Published var customer: Customer
        
        private var cancellables: Set<AnyCancellable> = []
        
        var id = ""
        var status: StatusEnum
        
        init(customer: Customer) {
            self.customer = customer
            self.status = customer.status
            $customer
                .compactMap { $0.status }
                .assign(to: \.status, on: self)
                .store(in: &cancellables)
        $customer
                .compactMap { $0.id }
                .assign(to: \.id, on: self)
                .store(in: &cancellables)
        }
        
        func update(customer: Customer) {
            customerRepository.update(customer)
        }
    }
    

    然后,在视图中使用这个新的状态变量:Text(customerViewModel.status.description)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-12
      • 1970-01-01
      • 2015-06-04
      相关资源
      最近更新 更多