@State
@State 应该仅用于简单的值类型,如字符串、整数、布尔值或结构体。
@State priate var isShow: Bool = false
@StateObject
@StateObject 用于在视图中声明和管理一个 ObservableObject。这是一个引用类型,可以包含复杂的数据和业务逻辑。@StateObject 确保对象的生命周期由 SwiftUI 管理,只有在视图创建时初始化一次。它适用于需要观察和响应状态变化的复杂对象。
- 定义一个遵循 ObservableObject 协议的类:
class UserSettings: ObservableObject {
@Published var username: String = "Guest"
}
- 在视图中使用 @StateObject 管理 UserSettings 对象:
struct ContentView: View {
@StateObject private var settings = UserSettings()
var body: some View {
VStack {
Text("Username: \(settings.username)")
Button("Change Username") {
settings.username = "John Doe"
}
}
}
}
使用 @State 来管理视图的简单本地状态。
使用 @StateObject 来管理需要观察的复杂对象的状态,确保它们在视图的生命周期内只初始化一次。
@Bind
可以将值类型的属性改变为引用类型传递值。在子视图中修改值, 可以触发父视图中 @State 修饰的对应属性的值, 从而可以触发父视图的body属性, 重新渲染UI。
在 Swift 5.1 中,对一个由 @ 符号修饰的属性,在它前面使用 $ 所取得的值,被称为投影属性 (projection property)。
struct SubView: View {
@Binding var isEnable: Bool
var body: some View {
Text("View1")
}
}
struct ParentView: View {
@State var isEnable: Bool
var body: some View {
SubView(isEnable: $isEnable)
}
}
ObservableObject协议
用来修饰类类型, 需要结合 @Published 和 @EnvironmentObject 使用, 见下面
@Published 和 @ObservedObject
可以被 SwiftUI 观察的属性。或者叫绑定的属性
class Model: ObservableObject {
@Published var title: String = "hello"
}
struct CustomView: View {
@ObservedObject var model: Model
var body: some View {
Text(model.title)
}
}
@ObservedObject 和 @StateObject 的区别
- 生命周期管理:
• @StateObject: 视图创建和管理对象的生命周期。确保对象在视图的生命周期内只初始化一次。
• @ObservedObject: 观察一个外部管理的对象的变化,不管理对象的生命周期。
- 使用场景:
• @StateObject: 用于视图本身创建和拥有的对象。
• @ObservedObject: 用于引用和观察视图外部创建和传入的对象。
@EnvironmentObject
如同单例对象, 进行页面之间的数据传递, 使用环境对象, 你可以在整个程序的任意页面设置和读取该对象。
class Model: ObservableObject {
var title: String = "hello"
}
struct CustomView: View {
@EnvironmentObject var model: Model
var body: some View {
Text(model.title)
}
}
@Environment
-
@EnvironmentObject 和 @Environment 都可以自在环境中存储和读取数据 但是 @Environment 需要根据预定义的键, 获取对应的值。
-
并且 @Environment 可以获取系统定义的固定属性。
要使用 @Environment, 必须要先定义一个遵循EnvironmentKey 协议的结构体。
private struct MyEnvironmentKey: EnvironmentKey {
static let defaultValue: String = "Default value"
}
extension EnvironmentValues {
var myCustomValue: String {
get { self[MyEnvironmentKey.self] }
set { self[MyEnvironmentKey.self] = newValue }
}
}
struct ContentView: View {
@Environment(\.myCustomValue) var customValue: String
var body: some View {
VStack {
Text(customValue)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environment(\.myCustomValue, "My custom value")
}
}
@AppStorage
定义一个属性, 它拥有一个默认值, 并且使用了@AppStorage 属性包装器, 这样对该属性的存储和读取操作, 都将映射到键名为 nickname 的UserDefaults 中。
@AppStorage("nickname") var nickName: String = "Fate"
struct ContentView: View {
@AppStorage("nickname") var nickName: String = "Fate"
var body: some View {
VStack(spacing: 20) {
Text(nickName)
Button {
nickName = "Cris Paul"
print(UserDefaults.standard.value(forKey: "nickname") ?? "")
} label: {
Text("Change nickName")
}
}
.padding()
}
}
@SceneStorage
该属性的值被保存在不同的场景中, 应用于 iPad多个场景中使用不同的值
struct ContentView: View {
@SceneStorage("nickname") var nickname: String = ""
var body: some View {
VStack(spacing: 20) {
Text(nickname)
Button {
self.nickname = "Hobe"
} label: {
Text("change nickname Hobe")
}
Button {
self.nickname = "Jerry"
} label: {
Text("change nickname Jerry")
}
}
.padding()
}
}