SwiftUI_2_共享绑定


参考:

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),用来进行状态管理。

属性包装器(property wrapper):@State、@ObservedObject、@EnvironmentObject

@State 用于单一视图的本地状态,

@ObservedObject 从一个视图传递到另一个视图。

@EnvironmentObject 比它们都更进一步:可以把一个对象注入环境,以便任何子视图都可以自动获得该对象的访问能力

  

@State

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值类型

  • 对于 @State 修饰的属性的访问,只能发生在 body 或者 body 所调用的方法中。
  • 如果是读写都有,引用属性需要$开头,如果只读直接使用变量名即可

@Binding

@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 

@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

 @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)

相关