译自 www.hackingwithswift.com/books/ios-s…
更多内容,欢迎关注公众号 「Swift花园」
喜欢文章?不如来个 🔺💛➕三连?关注专栏,关注我 🚀🚀🚀
SwiftUI 的 environment 可以让我们以一种相当优雅的方式共享数据:任何视图都可以把数据发送到环境中,然后任何子视图都可以从环境中读出这些数据。更棒的是,如果一个视图改变对象,所有其他视图都会自动更新 —— 这是一种极为聪明的在大型应用中共享数据的方式。
我们的应用中有 TabView
,它包含了三个 ProspectView
实例,我们需要它们是基于相同的共享数据运作的三个不同的视图。这是 SwiftUI 环境工作机制的绝佳示例:我们可以定义一个类来存储 prospect,然后用一组 prospect 注入环境,以便所有视图可以按需读取。
新建一个 Swift 文件,取名 Prospect.swift,把 Foundation 导入替换为 SwiftUI,然后添加下面的代码:
class Prospect: Identifiable, Codable { let id = UUID() var name = "Anonymous" var emailAddress = "" var isContacted = false } 复制代码
是的,这里采用类而不是结构体是有意为之,因为这样能让我们直接修改类的实例,让它在所有视图之间同时更新。记住,SwiftUI 是自动处理变化的传播过程。
说到在多个视图间共享数据,SwiftUI 的 environment 有一大好处是它采用的是相同的 ObservableObject
协议,我们之前已经用它配合 @ObservedObject
属性包装器。这意味着,只要我们给属性标记 @Published
属性包装器 —— SwiftUI 自动为我们完成大部分工作。
把这个类添加到 Prospect.swift:
class Prospects: ObservableObject { @Published var people: [Prospect] init() { self.people = [] } } 复制代码
我们稍后回来修改这个类。
现在,我们要让所有的 ProspectView
实例共享单一的 Prospects
实例,以便它们都指向相同的数据。如果我们还是采用 UIKit 编写代码,那我需要大费口舌来解释实现这一点有多么困难,以及我们在确保所有变化合理传播这件事时要多么当心,但在 SwiftUI 中,我们只需要三步。
首先,我们添加一个属性到 ContentView
,创建一个 Prospects
的单例:
var prospects = Prospects() 复制代码
其次,我们需要发送这个属性到 SwiftUI 的环境中,以便所有的子视图可以访问它。因为 tab 被看作是 tab view 的子视图,所以如果我们把这个属性添加到 TabView
的环境,那么所有的 ProspectsView
实例都将能够访问它。
把这个 modifier 添加到 ContentView
的 TabView
:
.environmentObject(prospects) 复制代码
接下来我们需要所有的 ProspectsView
在创建时从环境中读出这个对象。这里用到一个新的属性包装器,叫 @EnvironmentObject
。把下面这个属性添加到 ProspectsView
:
@EnvironmentObject var prospects: Prospects 复制代码
以上就是全部的步骤 —— 我想没有比这个更简单的方式了。
重要: 当你是用 @EnvironmentObject
的时候,你是在显式地告诉 SwiftUI ,当视图创建时你的对象会存在于环境中。如果它不存在,你的应用将会立即崩溃 —— 因此,请千万小心,把环境对象当成一个隐式的未解包的可选型来处理。
很快我们将要添加代码实现通过扫描二维码来添加 prospect 的功能,现在我们要先添加一个导航栏,用于添加测试数据。
把 ProspectsView
的 body
属性修改为这样:
NavigationView { Text("People: \(prospects.people.count)") .navigationBarTitle(title) .navigationBarItems(trailing: Button(action: { let prospect = Prospect() prospect.name = "Paul Hudson" prospect.emailAddress = "paul@hackingwithswift.com" self.prospects.people.append(prospect) }) { Image(systemName: "qrcode.viewfinder") Text("Scan") }) } 复制代码
现在你会在 ProspectsView
视图里看到一个 “扫描” 按钮,点击它,为三个视图同时添加一个人 —— 无论点的是哪个 tab 里的按钮,你都会看到 count 增加。
我的公众号 这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~