@State和@StateObject之间有什么区别?

5
我创建了一个像这样的模型。
import Foundation

class Play:ObservableObject{
    @Published var name:String="Tayle"
    @Published var age:Int=12
}

它将在两个视图中使用。

例如:

struct Demo: View {
    //1
    @State private var play:Play = Play()
    //2
    //@StateObject private var play:Play = Play()
    var body: some View {
        NavigationView{
            NavigationLink(destination: PlayNameView(play: play)){
                Text("go to platnbame")
            }
        }
    }
}

struct PlayNameView:View{
    @ObservedObject var play:Play
    var body: some View{
        HStack{
            Text("Hello,\(play.name)")
            Button(action:{
                play.name="iop"
            }){
                Text("change the name to:iop")
            }
            
        }
    }
}

当我运行项目时,它们具有相同的行为。如果@StateObject可以实现这一点,那么为什么要选择@State?
2个回答

15

@State是一个变量,旨在保存诸如Bools、Integers、Strings、structs等值类型。苹果公司并不打算让@State用于引用类型,比如ObservableObjects,因为状态(State)只能存储值类型,比如Int,而不是类的实例。苹果在文档中表示:

不要使用state属性进行持久性存储,因为状态变量的生命周期与视图生命周期相同。相反,将它们用于管理仅影响用户界面的瞬态状态,比如按钮的突出显示状态、过滤器设置或当前选择的列表项。

简而言之,您可以使用@State变量来存储用户自启动以来单击按钮的次数,但不能用来存储另一个ObservableObject。此外,如果您查看此篇文章,该文章表明使用带有State的对象将不会导致视图的实际变量更新。这是因为再次引用文章所说:

因为我们使用了一个复杂的引用类型,状态本身的值永远不会更改。虽然state的属性num已经更改了,但是@State属性包装器并不知道这一点,因为它仅仅观察变量state, 而不是它的任何属性。对于SwiftUI而言,因为它只观察状态(state),它并不知道num已经发生了变化,因此从未重新渲染视图。

另一方面,@StateObject可以存储像ObservableObjects这样的东西。当对象的值更改时,它将导致视图更新,因为所有这些都被SwiftUI观察到。但是,这仅在使用@Published属性时才会发生,并且这些属性的任何更改都会再次导致视图重新渲染。还有一个重要的注意事项:@StateObject每次视图出现时都会创建一个新实例。如果您需要保留值,您需要从更根本的视图传递该对象。此外,@StateObject可以从视图外部更改,而@State变量只能作为私有和局部变量使用。有关详细信息,请参阅苹果公司的State文档:https://developer.apple.com/documentation/swiftui/state

资源:

  1. SwiftUI:@State、@Binding、@Environment、@EnvironmentObject的区别以及何时使用它们
  2. 什么是@StateObject属性包装器?
  3. ObservedObject、@State和@EnvironmentObject之间有什么区别?
  4. @State、@StateObject、@ObservedObject和@EnvironmentObject在SwiftUI中的比较

等一下,我怎么能在@StateObject中使用struct?StateObject需要变量符合ObservableObject的协议,而这是struct所做不到的! - Timmy
@NoeOnJupiter 你说得对 - 我已经修复了那个错误。 - user18457910
我的意思是,您仍然可以在类对象中使用@State,因为属性的重新分配会导致更新,这可能正是您想要的。 - Peter Lapisu

6
对于对象,使用@StateObject属性包装器。对于字符串、整型等,使用@State属性包装器。 @State:当我们观察存在于我们的ContentView中的属性时,我们使用此属性包装器。 @StateObject:当我们观察存在于我们的ContentView之外的属性时,如在我们的对象中,我们可以通过首先将该类符合ObservableObject协议并将该属性标记为@Published来观察该属性的变化。

3
哦不,那不对。在视图拥有对象时应该使用@StateObject...你描述的情况应该由@ObservedObject处理。 - Peter Lapisu

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