参考:
https://blog.csdn.net/weixin_45727359/article/details/109108544
https://zhuanlan.zhihu.com/p/141229504?from_voters_page=true
用 @EnvironmentObject 从环境中读取值
SwiftUI: 全局状态管理
在SwiftUI中,以单一数据源(single source of truth)为核心,构建了数据驱动状态更新的机制。其中引入了多种新的属性包装器(property wrapper),用来进行状态管理。
@State
用于单一视图的本地状态,
@ObservedObject
从一个视图传递到另一个视图。
@EnvironmentObject
比它们都更进一步:可以把一个对象注入环境,以便任何子视图都可以自动获得该对象的访问能力
struct User {
var firstName = "Bilbo"
var lastName = "Baggins"
}
struct ContentView: View {
@State private var user = User() //1
var body: some View {
VStack {
Text("Your name is \(user.firstName) \(user.lastName).") //2
TextField("First name", text: $user.firstName) //3
TextField("Last name", text: $user.lastName)
}
}
}
@State是一个属性包装器(property wrapper),被设计用来针对值类型进行状态管理;用于在Struct中mutable值类型
@Binding的作用是在保存状态的属性和更改数据的视图之间创建双向连接
将当前属性连接到存储在别处的单一数据源(single source of truth)
struct Product:Identifiable {
var isFavorited:Bool
var title:String
var id: String
}
struct FilterView: View {
@Binding var showFavorited: Bool //3
var body: some View {
Toggle(isOn: $showFavorited) { //4
Text("Change filter")
}
}
}
struct ProductsView: View {
let products: [Product] = [
Product(isFavorited: true, title: "ggggg",id: "1"),
Product(isFavorited: false, title: "3333",id: "2")]
@State private var showFavorited: Bool = false //1
var body: some View {
List {
FilterView(showFavorited: $showFavorited) //2
ForEach(products) { product in
if !self.showFavorited || product.isFavorited {
Text(product.title)
}
}
}
}
}
@StateObject 和 @ObservedObject 的区别就是实例是否被创建其的View所持有,其生命周期是否完全可控。
@ObservedObject创建的实例生命周期可能长于/短于/等于当前的View的生命周期
三段代码,三种结果,这也就是为什么苹果要新增@StateObject的原因——让开发者可以明确地了解并掌握实例的生命周期,消除不确定性!
苹果使用@StateObject一方面修复了之前的隐患,同时通过SwiftUI2.0众多新特性的引入,进一步完善了Data Flow的实现手段。
SwiftUI 2.0 —— @StateObject 研究
class User: ObservableObject {
@Published var firstName = "Bilbo"
@Published var lastName = "Baggins"
}
struct ContentView: View {
@ObservedObject private var user = User() //@ObservedObject
属性包装器只能用于符合ObservableObject
协议的类型
var body: some View {
VStack {
Text("Your name is \(user.firstName) \(user.lastName).")
TextField("First name", text: $user.firstName)
TextField("Last name", text: $user.lastName)
}
}
}
@EnvironmentObject
属性包装器是说明属性的数据是来自环境,而不是在本地创建的:
class User: ObservableObject {
@Published var name = "Taylor Swift"
}
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)
}
}
struct ContentView: View {
let user = User()
var body: some View {
VStack {
EditView().environmentObject(user)
DisplayView().environmentObject(user)
}
}
}
把 ContentView
改成下面这样:你会发现结果一样。我们现在是把 user
放到 ContentView
的环境中,但是因为 EditView
和 DisplayView
都是 ContentView
的子视图,所以它们自动继承了 ContentView
的环境。
VStack {
EditView()
DisplayView()
}
.environmentObject(user)