ios - SwiftUI MVVM 方法与视图中的变量
问题描述
我正在基于 MVVM 设计模式在 SwiftUI 中构建一个应用程序。我正在做的是这样的:
struct AddInvestment: View {
@ObservedObject private var model = AddInvestmentVM()
@State private var action: AssetAction?
@State private var description: String = ""
@State private var amount: String = ""
@State private var costPerShare: String = ""
@State private var searchText: String = ""
@State var asset: Asset?
var body: some View {
NavigationView {
VStack {
Form {
Section("Asset") {
NavigationLink(model.chosenAsset?.completeName ?? "Scegli asset") {
AssetsSearchView()
}
}
Section {
Picker(action?.name ?? "", selection: $action) {
ForEach(model.assetsActions) { action in
Text(action.name).tag(action as? AssetAction)
}
}
.pickerStyle(.segmented)
.listRowBackground(Color.clear)
}
Section {
TextField("", text: $amount, prompt: Text("Unità"))
.keyboardType(UIKit.UIKeyboardType.decimalPad)
TextField("", text: $costPerShare, prompt: Text("Prezzo per unità"))
.keyboardType(UIKit.UIKeyboardType.decimalPad)
}
}
}
.navigationTitle("Aggiungi Investimento")
}
.environmentObject(model)
.onAppear {
model.fetchBaseData()
}
}
}
然后我有我的 ViewModel,这个:
class AddInvestmentVM: ObservableObject {
private let airtableApiKey = "..."
private let airtableBaseID = "..."
private let assetsTableName = "..."
private let assetsActionsTableName = "..."
private let airtable = Airtable.init("...")
private var tasks = [AnyCancellable]()
@Published var chosenAsset: Asset?
@Published var assets = [Asset]()
@Published var assetsActions = [AssetAction]()
init() { }
func fetchBaseData() {
print("Fetching data...")
let assetActionsRequest = AirtableRequest.init(baseID: airtableBaseID, tableName: assetsActionsTableName, view: nil)
let assetsActionsPublisher: AnyPublisher<[AssetAction], AirtableError> = airtable.fetchRecords(request: assetActionsRequest)
assetsActionsPublisher
.eraseToAnyPublisher()
.sink { completion in
print("** **")
print(completion)
} receiveValue: { assetsActions in
print("** **")
print(assetsActions)
self.assetsActions = assetsActions
}
.store(in: &tasks)
}
}
现在,如您所见,我在视图上有一些属性绑定到一些文本字段。让我们考虑这些:
@State private var description: String = ""
@State private var amount: String = ""
@State private var costPerShare: String = ""
@State private var searchText: String = ""
记住 MVVM 模式,这些属性是否应该在 ViewModel 中声明并从那里绑定?或者这是一个正确的方法?
解决方案
我倾向于将视图视为一个设备或一组设备(iPhone、iPad、Mac 等)的应用程序人机界面的定义。我倾向于将模型视为应用程序逻辑所在的地方,它不属于任何视图(业务逻辑、数据操作、网络操作等)。我认为 ViewModel 是 View 需要使 View 工作的任何逻辑退出的地方,例如格式化数据以在 View 上显示。我认为您正在寻找视图所需的数据元素的单一事实来源。在我看来,当且仅当它特定于 View 时,它才应该存在于 ViewModel 中。任何关于应用程序的逻辑或数据都应该存在于模型中,而不是视图模型中。通过这样做,我使我的模型更可重用,更独立于视图。总是有边缘情况,我想如果我构建一个完全独立的第二个视图,是否需要重新创建这些数据或逻辑,比如一个通过 HTML/JavaScript/等与浏览器一起工作的视图。如果我必须使用新的视图层重新创建该数据或逻辑,那么我认为数据或逻辑属于模型。如果数据或逻辑特定于该 View 层,那么我会将其放入该 View 的 ViewModel 中。
使用上面的想法,您的 AddInvestment 类看起来就像我将放在模型中的东西,而不是 ViewModel。当然,这完全是一个品味问题,我认为这里没有任何一个正确的答案,但我认为我会在自己的应用程序中对其进行切片和切块。
推荐阅读
- amazon-web-services - AWS RDS 代理配置
- netsuite - 您如何防止对 NetSuite 交易产生总总税额的影响?
- visual-studio - CMakeSettings.json 环境变量不使用 Visual Studio 生成器传递给 CMake
- python - 在 TensorFlow 中导入训练数据
- python - 查找python中的json中是否存在路径
- angular - 如何使用 http 客户端以角度获取 Oauth 令牌
- azure - 从 Azure 门户创建本地网关与从描述中给出的链接下载之间的区别
- python - 在具有不同输入大小的网格上插值函数
- function - 如何在 Julia 中绘制函数
- asp.net-core - 添加其他身份验证提供程序但保留当前会话数据