Swiftui州管理基础知识
#mobile #ios #swift #swiftui

本文试图帮助像我这样的初学者了解有关Swiftui的基本知识。这是我刚开始时我希望存在的文章类型。希望能为您节省一些时间并挣扎。

随时用更正或一般反馈发表评论。


先决条件

为了真正了解Swiftui中的状态管理,为了跟随本文,您需要了解几件事:

  • 价值类型和参考类型之间的差异
  • 什么是房地产包装,并且大致工作的工作方式

如果您对这些主题没有足够的信心,请花点时间阅读以下文档:

否则,让我们潜水。


申请管道

在很高的级别上,每个应用程序都是一个管道,将某些事件作为输入(用户手势,系统通知,计时器等),并产生输出,大多数通常是通过在屏幕上绘制一些东西。

不同的框架在输入和输出之间具有不同的中间步骤。在Swiftui中,管道看起来大致是这样的:

Image description


短暂的观点

看一下管道中的重新创建视图。从视图中,我的意思是我们使用body属性的自定义structs,只是要清楚。

Image description

在理解SwiftUI中的应用状态时,这是关键点之一。许多其他概念是这一事实的直接后果:

每次发生事件并观察到的状态发生变化时都会处置并重新创建。

这意味着我们无法可靠地将任何数据保留在我们的观点中。我们需要一些其他(外部)来存储应用程序状态。

幸运的是,Swiftui在视图层次结构之外具有内置存储:我们可以使用:SwiftUi状态。该状态完全由框架管理,我们仅通过提供的API访问它。


触发视图重新创建

在管道中,您还可以看到,使Swiftui重新创建我们的观点,最终重新渲染屏幕的唯一方法是更新观察到的数据。

Image description

这意味着我们需要以某种方式告诉Swiftui查找视图的某些属性的变化,并且在重新创建视图时。


@状态

所以,回顾:

  • 我们需要一种将数据放在我们观点之外的Swiftui状态的方法
  • 我们需要告诉Swiftui观察某些属性的变化,因此该框架知道何时重新创建视图并重新渲染

@State属性包装器一次解决这两个问题。让我们看一下简单的应用程序及其状态布局。

Image description

@State为我们的属性创建一个可观察的容器,并将其放在视图之外。 Swiftui现在保持我们的视图与观察到的数据之间的联系。因此,下次重新创建此视图时,它可以将数据注入视图的相应属性。

演示


Source code of the example

请注意,Counter视图在内部带有print()init()

每当按下随机按钮时,您都会在Xcode控制台中看到一条消息,这意味着重新创建了Counter视图,但是count保留了相同的数字,因为它存储在外面每次创建视图时,视图并注入。


查看重新创造与视图失踪

值得一提的是,在创建新版本之前,在创建新版本和您的代码之前,有意将视图的视图处置旧版本之间的区别。

在后一种情况下,SwiftUi会注意到该视图不再是渲染屏幕的一部分,并且会释放该视图中保留的所有值。下次您的代码决定再次显示视图时,其属性将带回州的初始值。

这是这种效果的演示。


Source code of the example


无耻的插头
我尝试在my Twitter上定期发布有用的开发内容,请随时关注我ð


@state带有参考类型

一个常见的误解是,您不能将@State与类别类型类型一起使用。您绝对可以,没有技术限制。

您只需要记住,您用@State包装的属性将包含参考,而引用将是Swiftui在该州存储并观察更改的唯一一件事。

请记住,如果您更新参考类型的属性,则其参考将不会更改。因此,对于Swiftui来说,看起来什么都没发生。

,但是@State不在乎可观察的容器并放入状态,它将与价值类型相同的方式进行。

Image description

如果您尝试运行此代码,则会发现它不起作用。


Source code of the example

在这里,我通过使用increment()来更新count属性,并尽可能更新。唯一的事情是,生活在Swiftui状态的参考文献永远不会改变,因此视图永远不会重新创建,并且屏幕永远不会更新。

从逻辑上讲,要修复此示例,我们需要每次点击按钮时更新参考。


Source code of the example

这有效,但是在大多数情况下,这并不是我们真正想要的解决方案。在很多情况下,每次重新创建一个实例可能会浪费,更不用说以这种方式编写的代码并不能很好地传达意图。我们想在计数器上增加计数,而不是每次全新的柜台。


observableObject, @obseverObject和@publined

这三个游戏一起播放,使我们有一种方法来更改参考类型的单个属性,并仍然对Swiftui进行交流更改,因此它知道重新渲染。

ObservableObject是您在参考类型上采用的协议,@ObservedObject是一个属性包装器,可容纳参考。

通过在属性上使用@ObservedObject,您基本上是对Swiftui说的,以查看该属性所含的对象内部。查看内部并订阅用@Published标记的属性的更改。

@Published用可观察的容器在参考类型上包装属性,就像@State为查看属性一样。

这就是在计数器应用程序的代码中的外观。

Image description
Source code of the example

现在,它可以与每次重新创建柜台重新创建柜台一起使用。

不幸的是,这种方法有一个缺陷,您可以在上图中看到它。 Swiftui状态是空的。 @ObservedObject不会像@State那样将数据放在视图之外。如果在视图中创建对象,则每次重新创建视图时,对象也将被重新创建。

这是这种效果的演示。


Source code of the example

请注意,每次按下随机按钮时,在顶部的计数器如何重置。当我们更新random属性时,SwiftUi执行ContentView的主体,并在此过程中重新创建CounterView。新创建的CounterView每次都以Counter的新实例。


@StateObject

这是@StateObject可以帮助我们的地方。它做的所有与@ObservedObject相同的事情,但此外还将观察到的属性放入视图层次结构之外的状态。

Image description

在下面,观看带有随机按钮的演示,它此时在counter属性上使用@StateObject


何时使用@ObseverObject而不是@stateObject?

似乎我们只需要一直使用@StateObject而忘记@ObservedObject即可。但是当您两者都需要时,有一个很好的用例。

在创建对象的视图中使用@StateObject。当视图从外部接收对象时,请使用@ObservedObject

考虑此示例:

Image description
Source code of the example

请注意,即使在同一Counter实例上观察两个视图并观察,Swiftui state也仅保留count属性的一个值。这是因为我们在CounterView上使用了@ObservedObject,它没有将任何东西放入状态。


谢谢您的阅读,希望它有帮助! ð

My Twitter如果您想伸出援手。