我觉得这个问题已经在某个地方被问过,但我找不到太多。
当使用变量来更新 UI 时,我们何时/为什么要在视图中使用
@State
,而不是在 ViewModel 中使用 @Published
?
这是在我试图掌握 MVVM 架构的背景下进行的。我通常理解其中的差异,只是当涉及到两者都可以轻松以相同方式完成的事情时。
下面,我有 2 个示例执行相同的操作,但一个使用
@State
,而另一个使用 @Published
和 ViewModel。一种方法是否比另一种更好(用于更新 UI 目的?)
@State
示例:
struct MyView: View {
@State var backgroundIsRed = false
var body: some View {
ZStack {
if backgroundIsRed {
Color.red
} else {
Color.green
}
}
.onTapGesture { backgroundIsRed.toggle() }
}
}
@Published
示例:
class ViewModel: ObservableObject {
@Published var backgroundIsRed = false
}
struct MyView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
ZStack {
if viewModel.backgroundIsRed {
Color.red
} else {
Color.green
}
}
.onTapGesture { viewModel.backgroundIsRed.toggle() }
}
}
例如,我想说“已发布”方法可以帮助您为虚拟机创建测试结构。
以您的示例为例,您可以创建一个协议:
protocol ViewModelProtocol {
var backgroundIsRed: Bool { get }
var date: Date { get } // Created for example purposes
}
然后:
class ViewModel: ViewModelProtocol, ObservableObject {
@Published var backgroundIsRed = false
@Published var date = Date()
}
class ViewModelMock: ViewModelProtocol, ObservableObject {
@Published var backgroundIsRed = true
@Published var date = Mock.Date
}
struct MyView: View {
@StateObject var viewModel: ViewModelProtocol = ViewModel()
//@StateObject var viewModel: ViewModelProtocol = ViewModelMock()
var body: some View {
ZStack {
if viewModel.backgroundIsRed {
Color.red
} else {
Color.green
}
}
.onTapGesture { viewModel.backgroundIsRed.toggle() }
}
}
另一方面,状态方法提供了一种更直接的方式来实现逻辑。
除此之外,没有任何特别的理由认为一个比另一个更好。 希望这可以帮助您选择在每种情况下应该使用哪一个。
@State
和 @Published
在 SwiftUI 中具有不同的用途:
@State
:此属性包装器用于在 SwiftUI 视图中声明状态信息。它通常用于视图内的本地状态,这意味着数据仅与该特定视图相关,不需要在多个视图之间共享或在视图的生命周期之外保留。 @State 对于管理诸如当前是否按下按钮、选择器中的当前选择或是否呈现模式等事情很有用。
@Published
:此属性包装器与 ObservableObject 协议结合使用来创建可观察对象。它通常在 SwiftUI 应用程序中使用 MVVM 模式来表示 ViewModel 层。 @Published
用于公开 ViewModel 中 View 观察到的更改的属性。当标有 @Published 的属性发生更改时,它会自动触发视图来更新其 UI 中任何受影响的部分。
何时使用每种:
使用
@State
来管理简单的、特定于视图的状态,不需要与其他视图共享或保留。
当您的数据需要在多个视图之间共享或需要在单个视图的生命周期之外保留时,请在 ViewModel 中使用 @Published
。
总之,@State 用于管理本地的、特定于视图的状态,而
@Published
用于管理共享状态并促进视图与其关联的 ViewModel 之间的通信。
因此,如果状态非常本地化且简单,则示例 1 可能会被认为更好。如果您预计需要与其他视图共享此状态,或者您更喜欢遵循更结构化的架构模式(如 MVVM),则示例 2 会更好。
我们在 SwiftUI 中不需要 MVVM,因为
View
结构已经是视图模型,即它保存 SwiftUI 用于创建/更新/删除屏幕上实际 UIView
对象的数据。如果您使用实际对象来完成这项工作,那么您会添加不必要的间接层,并且会出现一致性错误,而 SwiftUI 巧妙地使用值语义正是为了消除这种错误。
最好将
@StateObject
视为 @State
,但当您需要引用类型时,例如您想要异步加载/保存/同步数据。鉴于我们有更强大的 .task
修饰符,现在这种情况并不常见。
如果您的目标是对相关变量进行分组并具有可测试的逻辑,只需将
@State var
与自定义结构一起使用,这比正确实现 @StateObject
实现要简单得多。但是,您必须首先学习 mutating func
的逻辑。另外,如果您想访问自定义结构体中的 @Environment
,您需要学习 DynamicProperty
。