@State
使用@State修饰某个属性后,SwiftUI将会把该属性存储到一个特殊的内存区域内,并且这个区域和View struct是隔离的;
当@State修饰的属性的值发生变化后,SwiftUI会根据该属性重新绘制视图;
struct ContentView: View {
@State private var str: String = ""
var body: some View {
VStack {
TextField("Placeholder", text: $str)
Text("\(str)")
}
}
}
@Binding
开发中,我们需要把一个View的属性,传递到一个子View中;
Swift中,值传递的形式是值传递,也就是说,传个子View的是值的拷贝;子视图对这个值进行了修改后,不会影响父视图;
使用@Binding修饰后,属性就变成了一个引用类型,这样子视图对值进行了修改后,父视图中的值也会发生变化
// 父视图
struct BindViewTest: View {
@State var count = 0
var body: some View {
VStack(alignment: .center) {
Text("\(count)").padding()
BindSubView(count: $count).padding()
}
.padding()
}
}
// 子视图
struct BindSubView: View {
@Binding var count: Int
var body: some View {
Button(action: {
count += 1
}) {
Text("增加")
}
}
}
struct class区别
struct 是值类型的valueType、 值类型的变量包含数据,会进行值的copy,存储在Stack栈中,struct速度更快
class是引用类型的ReferenceType,引用类型的变量,存储对他们数据的引用,存储在heap堆中
使用@Binding标记子画面中的content属性,并且在构造SubView时,使用$符号将String类型转换为Binding<String>类型,此时,SubView持有的是主View的content的投影属性,无论我们通过点击ContentView还是通过点击SubView来修改content的值,两个View均会同步更新。
@ObservableObject
对实例进行监听,其用处和@State非常相似,只不过必须是对象,而且这个被监听的对象可以被多个视图使用。需要注意用法
class DelayedUpdater: ObservableObject {
@Published var value = 0
init() {
for i in 1...10 {
DispatchQueue.main.asyncAfter(deadline: .now() + Double(i)) {
self.value += 1
}
}
}
}
struct ContentView: View {
@ObservedObject var updater = DelayedUpdater()
var body: some View {
VStack {
Text("\(updater.value)").padding()
}
}
}
说明:
- 绑定的数据是一个对象。
- 被修饰的对象,其类必须遵守ObservableObject协议
- 此时这个类中被@Published修饰的属性都会被绑定
- 使用@ObservedObject修饰这个对象,绑定这个对象。
- 被@Published修饰的属性发生改变时,SwiftUI就会进行更新。
- 这里当value值会随着时间发生改变。所以updater对象也会发生改变。此时文本视图的内容就会不断更新。
@EnvironmentObject
在多视图中,为了避免数据的无效传递,可以直接将数据放到环境中,供多个视图进行使用。
struct EnvView: View {
@EnvironmentObject var updater: DelayedUpdater
var body: some View {
Text("\(updater.value)")
}
}
struct BtnvView: View {
@EnvironmentObject var updater: DelayedUpdater
var body: some View {
Text("\(updater.value)")
}
}
struct ContentView: View {
let updater = DelayedUpdater()
var body: some View {
VStack {
//EnvView().environmentObject(updater)
//BtnvView().environmentObject(updater)
EnvView()
BtnvView()
}.environmentObject(updater)
}
}
说明:
- 给属性添加@EnvironmentObject修改,就将其放到了环境中。
- 其他视图中想要获取该属性,可以通过.environmentObject从环境中获取。
- 可以看到分别将EnvView和BtnvView的属性分别放到了环境中之后我们ContentView视图中获取数据时,可以直接通过环境获取。
- 不需要将数据传递到ContentView,而是直接通过环境获取,这样避免了无效的数据传递,更加高效
- 如果是在多层级视图之间进行传递,会有更明显的效果。
AppStorage
AppStorage是一个全局的存储,它是使用UserDefaults来做持久化的,所以我们可以在app中任何地方获取使用它。它也是用于轻量级存储,例如app的设置信息。
struct AppStorageDemo: View {
// @AppStorage userDefaults 全局的
@AppStorage("message") var message:String = ""//userDefaults
var body: some View {
VStack{
Text("本地存储数据:\n\(message)")
TextField("请输入要存储的信息", text: $message).padding(10).border(.orange,width: 2)
Button("按钮存储") {
message = "按钮存储信息"
}.font(.title)
}.padding()
}
}
@SceneStorage swiftUI接管的 只能用在View上
网友评论