美文网首页
swiftUI中的属性装饰器

swiftUI中的属性装饰器

作者: Mjs | 来源:发表于2023-04-22 15:25 被阅读0次

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

说明:

  1. 绑定的数据是一个对象。
  2. 被修饰的对象,其类必须遵守ObservableObject协议
  3. 此时这个类中被@Published修饰的属性都会被绑定
  4. 使用@ObservedObject修饰这个对象,绑定这个对象。
  5. 被@Published修饰的属性发生改变时,SwiftUI就会进行更新。
  6. 这里当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上

相关文章

网友评论

      本文标题:swiftUI中的属性装饰器

      本文链接:https://www.haomeiwen.com/subject/hemsjdtx.html