SwiftUI:何时使用 @State vs @Published

7
我感觉这是一个已经有人问过的问题,但我找不到很多相关内容。
当我们使用变量更新UI时,我们何时/为什么要在视图中使用@State,而不是在ViewModel中使用@Published
这是在我试图掌握MVVM架构的背景下。我通常了解它们之间的区别,只是对于两者都可以轻松完成同样任务的情况下,不知道哪种方法更好。
下面是两个例子,它们实现了相同的功能,但一个使用@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() }
    }
}

3
从技术上讲,SwiftUI 是以 MVVM 方法为设计思路的。尽管如此,许多开发人员决定跳过 ViewModel 直接从模型到视图。这取决于你的观点 - 这篇文章讨论了如何实现 MVVM,而这篇帖子则持反对态度。 - user20384561
5
你的来源是“SwiftUI旨在支持MVVM架构”是什么? - jnpdx
2
在您的示例中,除了视图模型版本需要创建一个额外的类(用于视图模型)之外,几乎没有什么区别。它没有任何好处,因此我会选择状态版本。 - jnpdx
2
你的例子过于简化了,因为属性在视图中被使用和更新,State 属性包装器是显而易见的选择,但还有许多更复杂的用例/场景,所以在这里得出任何结论都是没有意义的。 - Joakim Danielson
2
如果只有视图读写此属性,那么为什么要在逻辑/流程中涉及另一种类型,因为它显然是视图内部的内容? - Joakim Danielson
显示剩余6条评论
2个回答

4
例如,我会说“发行版”方法可以帮助您为虚拟机创建测试结构。
以您的示例为例,您可以创建一个协议:
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() }
    }
}

另一方面,国家方法提供了一种更直接的实现逻辑的方式。 除此之外,没有特别的理由认为哪种方法比另一种更好。 希望这可以帮助您选择在每种情况下应该使用哪种方法。

-2
在SwiftUI中,我们不需要MVVM,因为View结构体已经是视图模型,即它保存了SwiftUI用于创建/更新/删除实际的UIView对象所使用的数据。如果您使用实际的对象来完成此任务,则会添加不必要的间接层,并且会出现SwiftUI clever use of value semantics旨在消除的一类一致性错误。
最好将@StateObject视为@State,但用于当您需要引用类型时,例如,您想异步加载/保存/同步数据。现在很少需要这样做,因为我们有更强大的.task修改器。
如果您的目标是将相关变量分组并具有可测试的逻辑,请使用带有自定义结构的@State var,这比获取正确的@StateObject实现要简单得多。但是,您必须先学习mutating func以便处理逻辑。此外,如果您想在自定义结构中访问@Environment,则需要学习DynamicProperty

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接