专栏首页韦弦的偶尔分享SwiftUI:使用 @EnvironmentObject 从环境中读取自定义值

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

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将自动确保共享同一环境对象的所有视图在更改时都会更新。

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

class User: ObservableObject {
    @Published var name = "Taylor Swift"
}

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

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

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属性中。如果在环境中找不到用户,您的代码就会

,因此请小心

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

struct ContentView: View {
    let user = User()

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

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

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 为什么SwiftUI的视图使用结构体?

    如果您曾经为UIKit或AppKit(Apple的iOS和macOS原始用户界面框架)编程,您会知道它们使用类而非结构体来构造视图。SwiftUI并非如此:我们...

    韦弦zhy
  • SwiftUI:集成 MapKit

    自从2007年第一台设备问世以来,地图就一直是iPhone的核心功能,开发者几乎已经可以使用底层框架了。它叫做 MapKit,和UIKit一样,如果我们不介意进...

    韦弦zhy
  • Hacking with iOS: SwiftUI Edition 视图和修饰符项目——挑战

    这个技术项目旨在深入探究特定的SwiftUI主题,我希望您在这里学到了很多有关视图和修饰符的知识——为什么SwiftUI的视图使用结构体,为什么some Vie...

    韦弦zhy
  • MySQL从删库到跑路_高级(三)——视图

    视图是由SELECT查询语句所定义的一个虚拟表,是查看数据的一种非常有效的方式。视图包含一系列带有名称的数据列和数据行,但视图中的数据并不真实存在于数据库中,视...

    良月柒
  • MySQL视图的创建与使用

    视图是MySQL的一种虚拟表,实际的表我们可以看到每一行的数据,而视图是另一种形式的表,他可以将任何的查询结果变成一种虚拟的表方便下一次进行查询。

    大猫的Java笔记
  • Mysql进阶三板斧(一)带你彻底搞懂View视图的原理及应用

    既然视图的定义是基于基本表的,哪为什么还要定义视图呢?这是因为合理地使用视图能够带来许多好处:

    陈哈哈
  • MySQL 视图

    看到这里,或许你已经对MySQL 的基本操作了如指掌,这篇文章讲解MySQL高级功能中 视图的概念及其用法。

    技能锦囊
  • MySQL 视图

    ​看到这里,或许你已经对MySQL 的基本操作了如指掌,这篇文章讲解MySQL高级功能中 视图的概念及其用法。

    技能锦囊
  • AI综述专栏 | 孙仕亮:多视图机器学习综述

    在科学研究中,从方法论上来讲,都应先见森林,再见树木。当前,人工智能科技迅猛发展,万木争荣,更应系统梳理脉络。为此,我们特别精选国内外优秀的综述论文,开辟“AI...

    马上科普尚尚
  • MySQL(十)之视图

    前言 前面给大家介绍了查询语句,感觉写的还不错的,喜欢的可以去查看。今天给大家分享的是MySQL中的视图。 视图(View):视图是由查询结果形成一张虚拟的表。...

    用户1195962

扫码关注云+社区

领取腾讯云代金券