首页 > 解决方案 > SwiftUI - 如何将日期字符串从日期选择器传回查看模型

问题描述

我想要完成的事情

我有一个代表日期选择器的视图和另一个代表特定日期的锻炼课程列表的视图。当用户更改日期选择器视图中的日期时,我想更新锻炼列表。我正在遵循 MVVM 设计,我基本上希望在我的视图模型中保持状态(日期字符串和与该日期有关的锻炼列表)并将其传递给我的视图。

stateDate当用户通过日期选择器选择一个新日期并让它在另一个视图中填充该字符串时,我想首先在我的视图模型中更新我的变量。最终目标是更新我从中提取数据的 Firestore 中的路径,以便我可以提取新数据。

当用户在我的一个视图中通过日期选择器选择新日期时,如何更新视图模型中的 @Published 变量?

源代码段

锻炼日期选择器视图

import SwiftUI

struct WorkoutDatePicker: View {
    @ObservedObject var viewModel = WorkoutClassViewModel()
    var body: some View {
        Form {
            DatePicker("Date",
                       selection: $viewModel.stateDate,
                       displayedComponents: [.date])
            Text("Your current date is \(viewModel.stateDate)")
        }   
    }
}

WorkoutClassViewModel 视图模型

import Foundation
import FirebaseFirestore

class WorkoutClassViewModel: ObservableObject {
    
    @Published var workoutClasses = [WorkoutClass]()
    @Published var stateDate = Date()
    
    private var db = Firestore.firestore()
    
    func fetchData() {
//        let dateString = getDateString(date: userData.date,format: "MM-dd-YYYY")
//        db.collection("schedules/\(dateString)/classes").addSnapshotListener { (querySnapshot, error) in
        db.collection("schedules/2021-07-18/classes").addSnapshotListener { (querySnapshot, error) in
            guard let documents = querySnapshot?.documents else {
                print("No documents")
                return
            }
            
            self.workoutClasses = documents.map { (queryDocumentSnapshot) -> WorkoutClass in
                let data = queryDocumentSnapshot.data()
                let id = queryDocumentSnapshot.documentID
                let reservationCnt = data["reservationCnt"] as? Int ?? 0
                let workoutType = data["workoutType"] as? String ?? ""
                return WorkoutClass(id: id, reservationCnt: reservationCnt,  workoutType: workoutType)
            }
        }
    }

}

类视图视图

import SwiftUI

struct ClassView: View {
    @ObservedObject var viewModel = WorkoutClassViewModel()
    var body: some View {
        VStack{
            WorkoutDatePicker()
            
            NavigationView {
                List(viewModel.workoutClasses) { workoutClass in
                    VStack(alignment: .leading) {
                        Text(workoutClass.workoutType).font(.title)
                    }
                }.onAppear() {
                    self.viewModel.fetchData()
                }
            }
        }    
    }
}

我是 SwiftUI 和 iOS 开发的新手,所以任何建议都是好建议!

标签: mvvmswiftui

解决方案


现在,您有两个不同的WorkoutClassViewModel. 当一个更新时,另一个不知道日期已更改。为了解决这个问题,您可以WorkoutClassViewModel通过传递对子视图 ( WorkoutDatePicker) 的引用来共享相同的内容。这在这个问题的另一个答案中得到了说明。

另一种选择是将子视图的职责与仅选择日期分开,将 a 传递@Binding给子视图可以使用的:stateDate

struct WorkoutDatePicker: View {
    @Binding var date : Date //<-- Here
    var body: some View {
        Form {
            DatePicker("Date",
                       selection: $date,
                       displayedComponents: [.date])
            Text("Your current date is \(date)")
        }
    }
}

struct ClassView: View {
    @StateObject private var viewModel = WorkoutClassViewModel() //<-- Here
    var body: some View {
        VStack{
            WorkoutDatePicker(date: $viewModel.stateDate)
            Text("Date: \(viewModel.stateDate)")
            
            NavigationView {
                List(viewModel.workoutClasses) { workoutClass in
                    VStack(alignment: .leading) {
                        Text(workoutClass.workoutType).font(.title)
                    }
                }.onAppear() {
                    self.viewModel.fetchData()
                }
            }
        }
    }
}

推荐阅读