SwiftUI `@State` 关键字有啥作用?

Posted

技术标签:

【中文标题】SwiftUI `@State` 关键字有啥作用?【英文标题】:What does the SwiftUI `@State` keyword do?SwiftUI `@State` 关键字有什么作用? 【发布时间】:2019-10-19 16:18:51 【问题描述】:

SwiftUI tutorial 使用 @State 关键字来指示可变的 UI 状态:

@State var showFavoritesOnly = false

它提供了以下摘要:

状态是一个值或一组值,它可以随时间变化,并影响视图的行为、内容或布局。您可以使用带有 @State 属性的属性来向视图添加状态。

关键字究竟是什么意思? 改变@State 变量如何导致重新计算视图? body getter 中的其他变量如何不可变?

【问题讨论】:

这是全新的,我认为在 WWDC 期间将提供更多信息或进一步解释,所以我不明白为什么这么急于发布有关 SwiftUI 的问题,即使我了解很多渴望开始探索它。 @JoakimDanielson 这是个坏问题吗? 这在某种程度上是我的观点,也许这是一个好问题,也许不是。很难说,因为这都是新事物。 好吧,我真的很好奇这是如何实现的以及需要添加哪些语言功能。 @JoakimDanielson 你不能指望没有人问关于新技术的问题 【参考方案1】:

@State 关键字是 @propertyWrapper,这是最近在 Swift 5.1 中引入的功能。正如corresponding proposal 中所解释的,它是一种避免样板代码的值包装器。


旁注:@propertyWrapper 以前被称为 @propertyDelegate,但后来发生了变化。请参阅this post 了解更多信息。


official @State documentation 有以下说法:

SwiftUI 管理您声明为状态的任何属性的存储当状态值改变时,视图使其外观无效,并且 重新计算身体。使用状态作为单一事实来源 给定的观点。

State 实例不是值本身;这是一种手段 读取和改变值。要访问一个州的潜在价值, 使用它的 value 属性。

因此,当您初始化标记为 @State 的属性时,您实际上并没有创建自己的变量,而是提示 SwiftUI 在后台创建 "something" 来存储您的内容从现在开始设置并监控它!您的@State var 只是作为代表来访问此包装器

每次您的@State 变量被写入 时,SwiftUI 都会知道,因为它正在监视它。它还将知道@State 变量是否是从Viewbody读取的。使用此信息,它将能够重新计算在更改此变量后在其 body 中引用了 @State 变量的任何 View

【讨论】:

它们仍然被称为属性委托还是现在是属性包装器?也许两者都有:( 这是很好的信息,但这实际上是如何工作的:“当状态值发生变化时,视图使其外观无效并重新计算主体”?在 Integrating 视频中,意大利人说 SwiftUI 知道 state 属性在 body 中使用,它也知道它在哪个视图中。我不明白这怎么可能,是吗? @23inhouse 我已在我的帖子中对此进行了澄清。 TLDR:它们的意思相同,但首选@propertyWrapper @Gusutafu @propertyWrapper 是一个包装器,它不仅知道何时写入,还知道何时读取——这样,它就可以确定从哪些视图读取。我已在回答中对此进行了澄清。【参考方案2】:

WWDC video - Session 204 中的示例很好地解释了它(从 16:00 开始,报价从 20:15 开始)

@State 变量的一个特殊属性是 SwiftUI 可以观察它们何时被读取和写入。因为 SwiftUI 知道 zoomed 是在 body 中读取的,所以它知道视图的渲染依赖于它。这意味着 - 当变量更改时,框架将使用新的 @State 值再次请求 body

@State 作为属性包装器也在Data Flow Through Swift UI (5:38) WWDC 视频中进行了详细说明和证明。它展示了当我们需要不可变 (struct) View 中的可变值时,它如何解决问题。

【讨论】:

“因为 SwiftUI 知道 zoomed 是在正文中读取的” - Swift 中的什么机制使这成为可能? @Gusutafu 组合框架(发布和订阅)。 SwiftUI 提供订阅者,因此每次发布者发出变量已更改的消息时,它都会听到。作为响应,它调用body 来重新生成接口。 谢谢,但我一直在努力解决的问题是 如何 SwiftUI 或 State 本身可能知道 State 被用于特定身体!【参考方案3】:

如果你知道 React Native,让我补充一点。

@State 属性非常类似于 React Native 中的 this.state 对象。

例如:

struct Foobar: some View 
    @State var username = ""

class Foobar extends React.Component 
  constructor(props) 
    super(props);
    this.state = 
      username: '',
    ;
  

当您修改用户名变量时,它们将具有相同的效果,即重新呈现当前页面。

【讨论】:

【参考方案4】:

如果你点击@State,你可以看到它有几个getter。一个是Value,另一个是Binding<Value>。 SwiftUI 似乎在很大程度上依赖于响应式编程(以及他们新的 Combine 框架,并且由于我们看不到这些包装器的完整实现,我希望通过 @State 属性包装器存储的值由 @ 管理987654326@ 来自Combine。顾名思义,这实际上存储了当前值,然后可以使用$ 语法将其用作可绑定属性。

【讨论】:

【参考方案5】:

我喜欢斯坦福大学的 Paul Hegarty 教授的解释。他说@State 基本上将该变量转换为指向内存中其他位置的某个布尔值的指针,这就是值发生变化的地方。但是你的变量——现在是一个带有@State 的指针——并没有改变,总是指向内存中的那个地方。

【讨论】:

【参考方案6】:

如果您了解 C# 和 Windows 开发。 @Statex:BindBinding 不同时相似。在集合上,与 ObservableCollection 不同时相似。

正如 fredpi 所说,SwiftUI 正在列出带有 @State 属性委托的 vars 更新。

【讨论】:

【参考方案7】:

注意:- 接受的答案是正确的,但如果您试图寻找我在下面尝试过的更简单的解释


@State 属性包装器允许我们更改结构内的值。

注意:- 您不能将结构中的属性更改为 a 值类型,因此不允许。

struct ExampleTextView: View 

    // Declare a variable with state property wrapper
    @State private var shouldChangeText: Bool = false
    
    var body: some View 
        Text("Just an example")
            .foregroundColor(Color.white)
    

如果您想知道我们是否应该添加私有访问说明符?

是的,根据经验,Apple 建议不应使用 @State 属性 与其他视图共享,因为有更具体的属性包装器 @ObservedObject 和 @EnvironmentObject。

但如果它是值类型,那么如何改变它存储在哪里呢?

因此,每当我们使用@State 标记属性时,我们都会将其存储移出 从 struct 到 SwiftUI 管理的共享存储。

如果您想与 Swift 进行比较,这就是它的做法,

struct Example 
    var exampleType: String
    
    mutating func changeType() 
        exampleType = "Are we allowed to do this?"
    

信用:请注意,这个答案的灵感来自这篇帖子https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-state-property-wrapper

【讨论】:

以上是关于SwiftUI `@State` 关键字有啥作用?的主要内容,如果未能解决你的问题,请参考以下文章

通过更改 SwiftUI 中的 @State 变量来刷新视图不起作用

sklearn的ParameterSampler中的random_state参数有啥作用?

android:state_enabled有啥作用

无法更新/修改 SwiftUI 视图的 @state var

嵌入另一个视图时,SwiftUI 动画不起作用

SwiftUI数据流与界面绑定