所以我基本上有一个ViewModel用于整个屏幕,它有多个组件,数据来自不同的API请求/端点。
我目前正在做的是拥有一个Observable对象,我可以从View(典型的状态SwiftUI状态处理)中对该对象进行更改,并通过@Published属性发出更改。粗略示例:
class ViewModel: ObservableObject {
@Published private(set) var isFirstComponentLoading = true
@Published private(set) var isSecondComponentLoading = true
@Published private(set) var isThirdComponentLoading = true
@Published private(set) var firstComponent: FirstComponentModel?
private var api = SomeApi()
//Imagine the exact same for every other component
func loadFirstComponent() {
isfirstComponentLoading = true
Task {
let response = try await api.loadFirstComponent()
await MainActor.run {
firstComponentModel = response
isFirstComponentLoading = false
}
}
}
}
视图(超标准的东西):
struct ContentView: View {
@StateObject var vm = ViewModel()
var body: some View {
VStack {
if vm.isFirstComponentLoading {
LoadingView()
} else {
FirstComponentView()
}
}
}
虽然这似乎是完美的工作,我有两个问题:
- 我并不为每个加载状态都有一个变量+另一个变量也包含组件的模型而感到自豪,想知道在同一个ViewModel中跟踪多个加载状态的最佳方法是什么,我觉得我在这里遗漏了一些东西?
- 一旦所有请求都成功完成,我将如何运行自定义代码?
谢谢你,谢谢
3条答案
按热度按时间mlnl4t2r1#
一种选择是使用这样的枚举:
这样就不需要为每个选项维护两个变量,这可能会导致非法状态(假设
isPropertyOneLoading
的状态为true
,而propertyOne
实际上有一个值)。然后,您可以在视图中的
LoadableResource
的当前状态上只添加switch
。4si2a6ki2#
我很想知道一个更好的方法来做到这一点,但目前我这样做是通过记录我在后台运行的请求数量,并在每个请求完成时减少计数。当
RunningCount
等于0时,我更新IsLoading
Bool,以在视图上切换加载指示器,使所有数据都可用。通过将
FirstComponentModel
提取到ListFirstComponentModel
中,可以在每个单独的对象上设置单独的loadingStatus,ListFirstComponentModel
将从api.loadFirstComponent()
中设置5uzkadbs3#
@StateObject
不是为传统视图模型对象设计的,你需要学习View
结构层次,否则你基本上会尝试重新实现SwiftUI View结构已经做的事情:依赖性和变更跟踪。要在SwiftUI中使用async/await,请不要使用
Task {}
,使用适当的task和task(id: someChangingValue)
修饰符,但要做到这一点,首先需要删除该视图模型对象,创建一个View结构层次结构,并在父视图中使用@State,并向下传递let用于读取,Binding用于读取/写入。使用计算属性将数据从丰富的模型类型转换为简单的类型。这样,您就可以使用简单类型创建预览。您可以将API/manager/controller放在EnvironmentKey中,例如比如内置的authorizationController。