1.@AppStorage定义

@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
@frozen @propertyWrapper public struct AppStorage<Value> : DynamicProperty {

    public var wrappedValue: Value { get nonmutating set }

    public var projectedValue: Binding<Value> { get }
}

2.@SceneStorage定义

@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
@frozen @propertyWrapper public struct SceneStorage<Value> : DynamicProperty {

    public var wrappedValue: Value { get nonmutating set }

    public var projectedValue: Binding<Value> { get }
}

3.区别

两者定义一样,但SceneStorage它只在Views中能被获取到。 AppStorage是一个全局的存储,它是使用UserDefaults来做持久化的,所以我们可以在app中任何地方获取使用它。

本质上就是使用属性包装器@propertyWrapper对UserDefault的封装

如果使用了投影属性projectedValue,那么会实现双向绑定

示例:

struct ContentView: View {
    @AppStorage("message") var message:String = "";
    var body: some View{
        VStack{
            Text("本地存储数据:\(message)")
                .foregroundColor(.blue)
            TextField("请输入要存储的信息",text:$message)
                .textFieldStyle(DefaultTextFieldStyle())
                .padding(10)
                .offset(x: 30, y: 0)
            Button("存储"){
                self.message = "按钮存储信息"
            }
        }
    }
}

AppStorage如何使用

struct TestSwiftUIApp: App {
    @AppStorage(newUserKey)var newUser: Bool = true
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

取值

struct ContentView: View {
    @AppStorage(newUserKey) var newUser: Bool = true
    var body: some View{
        VStack{
            let text: String = (newUser == true) ? "1" : "0"
            Text("当前显示是\(text)")
            Button("点击修改值"){
                newUser = !newUser
            }
        }
    }
}

实践证明:在ContentView中@AppStorage(newUserKey) var newUser: Bool = true并不会覆盖之前的值

当然也可以使用强制解包声明

@AppStorage(newUserKey) var newUser: Bool!