本文试图帮助像我这样的初学者了解有关Swiftui的基本知识。这是我刚开始时我希望存在的文章类型。希望能为您节省一些时间并挣扎。
随时用更正或一般反馈发表评论。
先决条件
为了真正了解Swiftui中的状态管理,为了跟随本文,您需要了解几件事:
- 价值类型和参考类型之间的差异
- 什么是房地产包装,并且大致工作的工作方式
如果您对这些主题没有足够的信心,请花点时间阅读以下文档:
否则,让我们潜水。
申请管道
在很高的级别上,每个应用程序都是一个管道,将某些事件作为输入(用户手势,系统通知,计时器等),并产生输出,大多数通常是通过在屏幕上绘制一些东西。
不同的框架在输入和输出之间具有不同的中间步骤。在Swiftui中,管道看起来大致是这样的:
短暂的观点
看一下管道中的重新创建视图。从视图中,我的意思是我们使用body
属性的自定义structs
,只是要清楚。
在理解SwiftUI中的应用状态时,这是关键点之一。许多其他概念是这一事实的直接后果:
每次发生事件并观察到的状态发生变化时都会处置并重新创建。
这意味着我们无法可靠地将任何数据保留在我们的观点中。我们需要一些其他(外部)来存储应用程序状态。
幸运的是,Swiftui在视图层次结构之外具有内置存储:我们可以使用:SwiftUi状态。该状态完全由框架管理,我们仅通过提供的API访问它。
触发视图重新创建
在管道中,您还可以看到,使Swiftui重新创建我们的观点,最终重新渲染屏幕的唯一方法是更新观察到的数据。
这意味着我们需要以某种方式告诉Swiftui查找视图的某些属性的变化,并且在重新创建视图时。
@状态
所以,回顾:
- 我们需要一种将数据放在我们观点之外的Swiftui状态的方法
- 我们需要告诉Swiftui观察某些属性的变化,因此该框架知道何时重新创建视图并重新渲染
@State
属性包装器一次解决这两个问题。让我们看一下简单的应用程序及其状态布局。
@State
为我们的属性创建一个可观察的容器,并将其放在视图之外。 Swiftui现在保持我们的视图与观察到的数据之间的联系。因此,下次重新创建此视图时,它可以将数据注入视图的相应属性。
演示
请注意,Counter
视图在内部带有print()
的init()
。
每当按下随机按钮时,您都会在Xcode控制台中看到一条消息,这意味着重新创建了Counter
视图,但是count
保留了相同的数字,因为它存储在外面每次创建视图时,视图并注入。
查看重新创造与视图失踪
值得一提的是,在创建新版本之前,在创建新版本和您的代码之前,有意将视图的视图处置旧版本之间的区别。
。在后一种情况下,SwiftUi会注意到该视图不再是渲染屏幕的一部分,并且会释放该视图中保留的所有值。下次您的代码决定再次显示视图时,其属性将带回州的初始值。
这是这种效果的演示。
无耻的插头
我尝试在my Twitter上定期发布有用的开发内容,请随时关注我ð
@state带有参考类型
一个常见的误解是,您不能将@State
与类别类型类型一起使用。您绝对可以,没有技术限制。
您只需要记住,您用@State
包装的属性将包含参考,而引用将是Swiftui在该州存储并观察更改的唯一一件事。
请记住,如果您更新参考类型的属性,则其参考将不会更改。因此,对于Swiftui来说,看起来什么都没发生。
,但是@State
不在乎可观察的容器并放入状态,它将与价值类型相同的方式进行。
如果您尝试运行此代码,则会发现它不起作用。
在这里,我通过使用increment()
来更新count
属性,并尽可能更新。唯一的事情是,生活在Swiftui状态的参考文献永远不会改变,因此视图永远不会重新创建,并且屏幕永远不会更新。
从逻辑上讲,要修复此示例,我们需要每次点击按钮时更新参考。
这有效,但是在大多数情况下,这并不是我们真正想要的解决方案。在很多情况下,每次重新创建一个实例可能会浪费,更不用说以这种方式编写的代码并不能很好地传达意图。我们想在计数器上增加计数,而不是每次全新的柜台。
observableObject, @obseverObject和@publined
这三个游戏一起播放,使我们有一种方法来更改参考类型的单个属性,并仍然对Swiftui进行交流更改,因此它知道重新渲染。
ObservableObject
是您在参考类型上采用的协议,@ObservedObject
是一个属性包装器,可容纳参考。
通过在属性上使用@ObservedObject
,您基本上是对Swiftui说的,以查看该属性所含的对象内部。查看内部并订阅用@Published
标记的属性的更改。
@Published
用可观察的容器在参考类型上包装属性,就像@State
为查看属性一样。
这就是在计数器应用程序的代码中的外观。
现在,它可以与每次重新创建柜台重新创建柜台一起使用。
不幸的是,这种方法有一个缺陷,您可以在上图中看到它。 Swiftui状态是空的。 @ObservedObject
不会像@State
那样将数据放在视图之外。如果在视图中创建对象,则每次重新创建视图时,对象也将被重新创建。
这是这种效果的演示。
请注意,每次按下随机按钮时,在顶部的计数器如何重置。当我们更新random
属性时,SwiftUi执行ContentView
的主体,并在此过程中重新创建CounterView
。新创建的CounterView
每次都以Counter
的新实例。
@StateObject
这是@StateObject
可以帮助我们的地方。它做的所有与@ObservedObject
相同的事情,但此外还将观察到的属性放入视图层次结构之外的状态。
在下面,观看带有随机按钮的演示,它此时在counter
属性上使用@StateObject
。
何时使用@ObseverObject而不是@stateObject?
似乎我们只需要一直使用@StateObject
而忘记@ObservedObject
即可。但是当您两者都需要时,有一个很好的用例。
在创建对象的视图中使用@StateObject
。当视图从外部接收对象时,请使用@ObservedObject
。
考虑此示例:
请注意,即使在同一Counter
实例上观察两个视图并观察,Swiftui state也仅保留count
属性的一个值。这是因为我们在CounterView
上使用了@ObservedObject
,它没有将任何东西放入状态。
谢谢您的阅读,希望它有帮助! ð
My Twitter如果您想伸出援手。