前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SwiftUI:使用 @EnvironmentObject 从环境中读取自定义值

SwiftUI:使用 @EnvironmentObject 从环境中读取自定义值

作者头像
韦弦zhy
发布2020-09-10 18:30:18
9.5K0
发布2020-09-10 18:30:18
举报
\color{red}{\Large \mathbf{Hacking \quad with \quad iOS: SwiftUI \quad Edition}}
\color{red}{\Large \mathbf{Hacking \quad with \quad iOS: SwiftUI \quad Edition}}
{\Large \mathbf{潜力客户名单}}
{\Large \mathbf{潜力客户名单}}
{\Large \mathbf{Hot \ Prospects}}
{\Large \mathbf{Hot \ Prospects}}

SwiftUI的环境使我们可以使用来自外部的值,这对于读取Core Data上下文或视图的展示模式等很有用。但是我们也可以将自定义对象发送到环境中,并在以后将它们读出来,这使我们可以在复杂的应用程序中更轻松地共享数据。

您已经了解了如何使用@State处理单个视图的局部状态,以及@ObservedObject如何使我们在视图之间传递一个对象,以便我们可以共享它。好吧,@ EnvironmentObject更进一步:我们可以将对象放置到环境中,以便任何子视图都可以自动访问它。

假设我们在一个应用程序中有多个视图,所有视图都排成一排:视图A显示视图B,视图B显示视图C,C显示D,D显示E。视图A和E都希望访问同一对象,但是要从A到达E,您需要经过B,C和D,而他们并不关心该对象。如果我们使用@ObservedObject,则需要将我们的对象从每个视图传递到下一个视图,直到它最终到达可以使用该视图的视图E,这很烦人,因为B,C和D不在乎它。使用@EnvironmentObject,视图A可以将对象放入环境中,视图E可以从环境中读取对象,而视图B,C和D不必知道发生了什么。

环境对象的一个​​复杂性是其子对象的构成,因为视图可以访问的环境对象取决于其父视图。例如,如果视图A可以访问环境对象,而视图B在视图A的内部——即视图B放在A的body属性中——那么视图B也可以访问该环境对象。这意味着,如果视图A是导航视图,则所有压入导航堆栈的视图都可以访问同一环境。但是,如果视图A以工作表(sheet)的形式显示视图B,则它们不会自动共享环境数据,因此我们需要手动发送。Apple已将此工作表情况描述为他们想要修复的错误,因此我希望在以后对SwiftUI的更新中会有所改变。

在向您展示一些代码之前,还有最后一件事:环境对象使用您已经学过的ObservableObject协议,SwiftUI将自动确保共享同一环境对象的所有视图在更改时都会更新。

好的,让我们看一些代码,这些代码展示了如何使用环境对象在两个视图之间共享数据。首先,这是我们可以使用的一些基本数据:

代码语言:javascript
复制
class User: ObservableObject {
    @Published var name = "Taylor Swift"
}

如您所见,使用ObservableObject@Published就像我们以前学到的那样——您积累的所有知识将继续得到回报。

接下来,我们可以定义两个SwiftUI视图以使用我们的新类。这些将使用@EnvironmentObject属性包装器来表示此数据的值来自环境,而不是在本地创建:

代码语言:javascript
复制
struct EditView: View {
    @EnvironmentObject var user: User

    var body: some View {
        TextField("Name", text: $user.name)
    }
}

struct DisplayView: View {
    @EnvironmentObject var user: User

    var body: some View {
        Text(user.name)
    }
}

@EnvironmentObject属性包装器将自动在环境中查找User实例,并将其找到的内容放入user属性中。如果在环境中找不到用户,您的代码就会

{\mathbf{崩溃}}
{\mathbf{崩溃}}

,因此请小心

现在,我们可以将这两个视图放在一个地方,并发送一个User实例供它们使用:

代码语言:javascript
复制
struct ContentView: View {
    let user = User()

    var body: some View {
        VStack {
            EditView().environmentObject(user)
            DisplayView().environmentObject(user)
        }
    }
}

这就是使我们的代码正常工作所要做的一切——您现在就可以运行该应用并更改文本字段,以查看其值显示在下面的文本视图中。当然,我们可以在单个视图中表示出来,但是通过这种方式,您可以确切地看到使用环境对象时通信的无缝性。

现在,这是最聪明的部分。尝试将ContentViewbody属性重写为:

代码语言:javascript
复制
VStack {
    EditView()
    DisplayView()
}
.environmentObject(user)

您会发现它的表现完全相同。现在,我们将用户置于ContentView环境中,但是由于EditViewDisplayView都是ContentView的子级,因此它们会自动继承其环境。

现在,您可能想知道SwiftUI如何在.environmentObject(user)@EnvironmentObject var user: User之间建立连接——如何知道将该对象放入正确的属性?

好吧,您已经了解到字典如何让我们使用一种类型作为键key,而另一种类型作为值。环境有效地使我们可以将数据类型本身用作键,并将类型的实例用作值。刚开始时,这有点令人费解,但可以这样想象:键是IntStringBool之类的,值是5,“ Hello”和 true,这意味着我们可以说“给我Int”,我们将得到5。

译自 Reading custom values from the environment with @EnvironmentObject

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档