【发布时间】:2020-05-08 10:15:13
【问题描述】:
问题
为了实现应用代码的简洁外观,我为每个包含逻辑的视图创建了 ViewModel。
一个普通的 ViewModel 看起来有点像这样:
class SomeViewModel: ObservableObject {
@Published var state = 1
// Logic and calls of Business Logic goes here
}
并像这样使用:
struct SomeView: View {
@ObservedObject var viewModel = SomeViewModel()
var body: some View {
// Code to read and write the State goes here
}
}
当 Views Parent 没有更新时,这可以正常工作。如果父级的状态发生变化,这个视图会被重绘(在声明性框架中很正常)。 但是 ViewModel 也会被重新创建并且之后不会保持状态。与其他框架(例如:Flutter)相比,这是不寻常的。
在我看来,ViewModel 应该保留,或者 State 应该保留。
如果我将 ViewModel 替换为 @State 属性并直接使用 int(在此示例中),它将保持持久状态并且不会重新创建:
struct SomeView: View {
@State var state = 1
var body: some View {
// Code to read and write the State goes here
}
}
这显然不适用于更复杂的状态。而且,如果我为@State 设置一个类(如 ViewModel),就会有越来越多的事情无法按预期工作。
问题
- 有没有办法不每次都重新创建 ViewModel?
- 有没有办法为
@ObservedObject复制@StatePropertywrapper? - 为什么@State 在重绘时保留 State?
我知道通常在内部视图中创建 ViewModel 是不好的做法,但可以通过使用 NavigationLink 或 Sheet 来复制这种行为。
有时,当您想到一个非常复杂的 TableView 时,将 State 保留在 ParentsViewModel 中并使用绑定是没有用的,其中 Cell 本身包含很多逻辑。
对于个别情况,总有一种解决方法,但我认为如果不重新创建 ViewModel 会更容易。
重复问题
我知道有很多关于这个问题的问题,都在谈论非常具体的用例。在这里我想谈谈一般问题,而不是太深入地讨论自定义解决方案。
编辑(添加更详细的示例)
当拥有一个改变状态的 ParentView 时,比如来自数据库、API 或缓存的列表(想想一些简单的事情)。通过NavigationLink,您可能会到达一个详细信息页面,您可以在其中修改数据。通过更改数据,反应式/声明式模式会告诉我们也更新 ListView,然后“重绘”NavigationLink,这将导致重新创建 ViewModel。
我知道我可以将 ViewModel 存储在 ParentView / ParentView 的 ViewModel 中,但这是 IMO 错误的做法。而且由于订阅被销毁和/或重新创建 - 可能会有一些副作用。
【问题讨论】:
-
您能找到解决方案吗?我最终创建了一个 environmentObject,因此它只有一个视图模型实例。
标签: swift swiftui declarative property-wrapper