SwiftUI 常用 Property Wrappers 之 State
🧠🔋
属性包装器 State
作为老iOS开发,之前一直在强调面向对象开发,而后引申出来的就是对象内存管理,MRC和ARC什么的,Apple 在新的SwiftUI里,摒弃了这些,大量使用了存储在栈上的内存结构--> Struct
结构体,这样就不需要开发来管理内存了。
那么如果在 Struct 里不能直接修改一个变量的值,同样在我们的 View 里也不可以,下面的代码会报错。
struct StateView: View {
var show: Bool = true
var body: some View {
Button {
show.toggle()
} label: {
Text(show ? "Show" : "Hide")
}
}
}
❌ Cannot use mutating member on immutable value: 'self" is immutable
另外一个问题,当我们改变某个变量的时候,View 是如何更新内容的呢?这就是我们现在学习的一个 Property Wrapper, Swiftul 使用 @State 来允许我们修改一个 struct 里的变量,同时更新 View。更深入的理解是 @State 把struct 存储的变量转移到 SwiftUl 管理的内存里,SwiftUl 可以便捷的销毁和重建 View,非常高效用户不会感觉到整个过程,也不会丢失我们已经存在的状态。
struct StateView: View {
@State var show: Bool = true
var body: some View {
Button {
show.toggle()
} label: {
Text(show ? "Show" : "Hide")
}
}
}
上面的代码在运行的时候就不会报错了,当我们点击文字的时候,因为 show 的变化,Swiftul 会销毁掉已经显示的 Show 文字的 View 根据 show 的值而显示 Hide 文字的 View,达到更新 View 的目的。
有过开发经验的同学一眼就看出来了,这不就是双向绑定
吗?更新模型,UI自动更新,更新UI,模型自动更新,就是这个意思。
更好的理解 State
struct StateView: View {
@State var number: Int = 6
var body: some View {
VStack {
Button {
number += 1
} label: {
Text("数字 +1")
}
StateDetailView(number: number)
}
}
struct StateDetailView: View {
var number: Int
// @State var number: Int
var body: some View {
Text("当前数字: \(number)")
}
}
}
在上面的例子里,对于 StateDetaiView 的 number,没有加 @State 的时候随着我们点击按钮数字会增加,而增加了@State 反而不会增加了,这是为什么呢?
这就是因为上面最开始说的 @State 的原理,@State 把 struct 存储的变量转移到 SwiftUI 管理的内存里,当没有@State 的时候,当 number 更新的时候会更新 StateDetailView 的 number,而显示的数字就是这个 number,但是当添加了 @State 的时候,StateDetailView 的 number 就是由 SwiftUI 管理的 number,这个时候更新的时候没有更新SwiftUl 管理的 number。
由于 @State 属性包装器是为了在视图层次结构内共享状态而设计的,因此通常最好将其用于简单的视图。对于复杂的状态管理,我们可能需要使用其他属性包装器,如 @ObservedObject 或@EnvironmentObject,之后我们再介绍。