什么是 @AppStorage
?
#
在 SwiftUI 中,@AppStorage
是一个属性包装器,用于便捷地访问 UserDefaults
中存储的数据。它提供了一种现代化和类型安全的方式来读取和存储轻量级的键值对数据,尤其适用于 持久化跨应用会话的简单设定(如用户偏好、配置信息等)。
当数据发生变化时,@AppStorage
会自动通知视图刷新,从而实现数据绑定和 UI 更新。
基本用法 #
使用 @AppStorage
表示一个绑定到 UserDefaults
的属性,你只需要提供一个键名。
示例 1:静态示例 #
import SwiftUI
struct ContentView: View {
@AppStorage("username") var username: String = "Guest" // 绑定 UserDefaults 中的 "username"
var body: some View {
VStack {
Text("Hello, \(username)") // 绑定的值改变时,视图会自动刷新
TextField("Enter your name", text: $username) // 修改绑定值
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
.padding()
}
}
解释: #
@AppStorage("username")
:- 将
username
属性绑定到UserDefaults
的键"username"
,初始值为Guest
。
- 将
- 自动监听:
- 当
username
属性的值被用户在TextField
中修改时,它会自动同步到UserDefaults
,并触发Text
视图重新渲染。
- 当
@AppStorage 支持的数据类型 #
AppStorage
支持以下常见类型,与 UserDefaults
基本一致:
- 基本数据类型:
Int
,Double
,Float
,Bool
,String
- 集合类型(如
Data
默认支持,但需手动编码数据)。 - 枚举(原始值必须是支持的类型,例如
String
或Int
)。
@AppStorage 使用案例 #
示例 2:存储布尔值(应用主题) #
import SwiftUI
struct ContentView: View {
@AppStorage("isDarkMode") var isDarkMode: Bool = false // 是否启用暗模式
var body: some View {
VStack {
Text("Current Theme: \(isDarkMode ? "Dark" : "Light")")
.padding()
Toggle("Enable Dark Mode", isOn: $isDarkMode)
.padding()
}
.preferredColorScheme(isDarkMode ? .dark : .light) // 根据用户偏好设置界面主题
}
}
解释:
isDarkMode
绑定到UserDefaults
中的"isDarkMode"
键。- 切换开关时,
UserDefaults
的值会更新,并自动切换应用主题。
为 @AppStorage
设置自定义数据类型
#
虽然 @AppStorage
默认支持基础数据类型,但对于一些复杂数据(如自定义对象或枚举),你需要做额外的处理。例如,利用枚举的原始值(RawValue),或将自定义类型序列化为可以存储的格式(如 JSON)。
示例 3:存储枚举值(原始值) #
import SwiftUI
enum AppTheme: String { // 定义枚举
case light, dark
}
struct ContentView: View {
@AppStorage("selectedTheme") var selectedThemeRaw: String = AppTheme.light.rawValue // 存储枚举原始值
var selectedTheme: AppTheme {
get { AppTheme(rawValue: selectedThemeRaw) ?? .light }
set { selectedThemeRaw = newValue.rawValue }
}
var body: some View {
VStack {
Text("Selected Theme: \(selectedTheme == .dark ? "Dark" : "Light")")
Button("Switch Theme") {
selectedTheme = (selectedTheme == .light) ? .dark : .light
}
}
.preferredColorScheme(selectedTheme == .dark ? .dark : .light)
}
}
解释:
selectedThemeRaw
存储枚举的原始值(String
类型)。- 提供了
selectedTheme
属性用于在 UI 和枚举数据之间转换。
示例 4:存储复杂对象(使用 JSON 编码) #
如果你需要存储复杂类型(如自定义对象),可以将它们转化为 Data
或 String
。
import SwiftUI
struct User: Codable {
var name: String
var age: Int
}
// 自定义 User 类型的 AppStorage
@propertyWrapper
struct AppStorageCodable<T: Codable>: DynamicProperty {
let key: String
let defaultValue: T
@AppStorage private var storedData: Data?
var wrappedValue: T {
get {
if let data = storedData {
return try! JSONDecoder().decode(T.self, from: data)
}
return defaultValue
}
set {
storedData = try? JSONEncoder().encode(newValue)
}
}
}
struct ContentView: View {
@AppStorageCodable("currentUser", defaultValue: User(name: "Guest", age: 0)) var currentUser
var body: some View {
VStack {
Text("Name: \(currentUser.name)")
Text("Age: \(currentUser.age)")
Button("Update User") {
currentUser = User(name: "John", age: 35) // 更新对象
}
}
}
}
解释:
AppStorageCodable
是一个自定义的属性包装器,用于将 Codable 类型转化为AppStorage
支持的Data
格式,并存储到UserDefaults
。- 自动对复杂数据(如
User
对象)进行序列化和反序列化。
@AppStorage 的注意事项 #
不要存储大量数据:
@AppStorage
的底层依赖UserDefaults
,而UserDefaults
更适合存储轻量级的配置(如布尔值、字符串、数字等),不推荐用来存储大数据(如图片或文件)。
避免密集操作:
UserDefaults
不是高性能存储,每次写入/读取都需要一定的性能开销。如果需要频繁修改或大量存储,考虑使用 Core Data 或 SQLite。
跨设备同步 iCloud(可选):
- 如果你希望
AppStorage
值在多台设备间同步,可以将存储的值绑定到共享的UserDefaults
容器(如iCloud
):@AppStorage("username", store: UserDefaults(suiteName: "iCloud.com.example.myapp")) var username: String = "Guest"
- ⚠️ 确保正确设置 App 的 iCloud 容器。
- 如果你希望
安全类型转换:
- 如果
@AppStorage
获取不到值(比如数据被外部清除),它会返回默认值(如果设置了)。确保在实现时正确定义默认值,防止应用崩溃。
- 如果
和其他 SwiftUI 数据持久化方式的对比 #
1. 和 @SceneStorage
的区别
#
@SceneStorage
适用于每个不同 “场景”(即窗口)的独立状态存储,而 @AppStorage
是全局共享的(所有场景访问同一份数据)。
属性 | 特性 | 用途 |
---|---|---|
@AppStorage | 持久化到 UserDefaults | 用于跨场景的设置或全局状态 |
@SceneStorage | 恢复场景级别状态 | 适用于多窗口场景,各窗口状态独立 |
2. 和 UserDefaults
的区别
#
@AppStorage
是现代化的、类型安全的,和 SwiftUI 绑定。但是底层仍然依赖于 UserDefaults
。
操作类型 | UserDefaults 方法 | @AppStorage (更简洁) |
---|---|---|
存储用户偏好 | UserDefaults.standard.set() | 使用简单变量即可 |
监听和 UI 更新 | 需要手动更新 | 自动完成数据绑定和 UI 刷新 |
总结 #
AppStorage
简化了UserDefaults
的使用,同时自动绑定到 SwiftUI 的视图更新机制。- 应用场景:存储轻量和重要的配置项,比如应用主题、用户语言、通知开关等。
- 进阶用法:通过枚举、自定义类型等扩展其功能。