Persistent Storage
SwiftUI 提供了一系列用于处理持久化存储的工具,旨在简化应用状态的保存与恢复。这些工具涵盖了从简单的用户偏好设置到复杂的 Core Data 数据管理。
SwiftUI 提供了一系列用于处理持久化存储的工具,旨在简化应用状态的保存与恢复。这些工具涵盖了从简单的用户偏好设置到复杂的 Core Data 数据管理。
AppStorage
AppStorage 是一个属性包装器,用于从 UserDefaults 中读取和写入值。它使得管理用户偏好设置变得非常简单,当存储的值发生变化时,视图会自动刷新。
基本用法
使用 @AppStorage 声明属性,指定存储的键(Key)和默认值。
struct SettingsView: View {
@AppStorage("isDarkMode") private var isDarkMode = false
@AppStorage("username") private var username = "Guest"
@AppStorage("fontSize") private var fontSize: Double = 14.0
var body: some View {
Form {
Toggle("Dark Mode", isOn: $isDarkMode)
TextField("Username", text: $username)
Slider(value: $fontSize, in: 10...30, label: { Text("Font Size") })
}
}
}支持的类型
AppStorage 支持以下基本类型:
BoolIntDoubleStringURLData- 遵循
RawRepresentable且RawValue为Int或String的枚举
enum Theme: String, CaseIterable, Identifiable {
case light, dark, system
var id: Self { self }
}
struct ThemeSettingsView: View {
@AppStorage("appTheme") private var selectedTheme: Theme = .system
var body: some View {
Picker("Theme", selection: $selectedTheme) {
ForEach(Theme.allCases) { theme in
Text(theme.rawValue.capitalized).tag(theme)
}
}
}
}defaultAppStorage
使用 defaultAppStorage(_:) 修饰符可以为视图层级中的 AppStorage 指定一个自定义的 UserDefaults 实例。这在需要与 App Group 共享数据或使用特定的 UserDefaults suite 时非常有用。
let customStore = UserDefaults(suiteName: "group.com.example.myapp")!
ContentView()
.defaultAppStorage(customStore)SceneStorage
SceneStorage 是一个属性包装器,用于保存和恢复每个场景(Scene)特有的数据。与 AppStorage 不同,SceneStorage 的数据是依附于特定场景的,当场景被销毁时,数据也会随之销毁(但在应用挂起或终止后重新启动时会尝试恢复)。
它非常适合用于状态恢复(State Restoration),例如保存当前选中的标签页、滚动位置或文本编辑器的内容。
基本用法
struct ContentView: View {
@SceneStorage("selectedTab") private var selectedTab = 0
@SceneStorage("noteContent") private var noteContent = ""
var body: some View {
TabView(selection: $selectedTab) {
TextEditor(text: $noteContent)
.tabItem { Text("Notes") }
.tag(0)
Text("Settings")
.tabItem { Text("Settings") }
.tag(1)
}
}
}注意事项
- 不要使用
SceneStorage存储敏感数据或关键业务数据,它仅用于 UI 状态恢复。 - 数据量应保持轻量。
- iPadOS 上支持多窗口,每个窗口都有独立的
SceneStorage。
Core Data Integration
SwiftUI 提供了与 Core Data 深度集成的工具,使得在视图中展示和操作 Core Data 数据变得直观。
Environment Value
首先,需要将 NSManagedObjectContext 注入到环境中。通常在 App 的入口处完成。
@main
struct MyApp: App {
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
}FetchRequest
@FetchRequest 用于从 Core Data 存储中获取数据。它会根据指定的排序描述符(Sort Descriptors)和谓词(Predicate)自动执行查询,并在数据变化时更新视图。
struct ItemListView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
predicate: NSPredicate(format: "isFavorite == true"),
animation: .default)
private var items: FetchedResults<Item>
var body: some View {
List {
ForEach(items) { item in
Text(item.timestamp!, formatter: itemFormatter)
}
.onDelete(perform: deleteItems)
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { items[$0] }.forEach(viewContext.delete)
try? viewContext.save()
}
}
}SectionedFetchRequest
@SectionedFetchRequest 是 @FetchRequest 的变体,用于支持分段(Sectioned)数据列表。它根据指定的属性对结果进行分组。
struct SectionedItemListView: View {
@SectionedFetchRequest(
sectionIdentifier: \.category,
sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
animation: .default)
private var items: SectionedFetchResults<String, Item>
var body: some View {
List {
ForEach(items) { section in
Section(header: Text(section.id)) {
ForEach(section) { item in
Text(item.timestamp!, formatter: itemFormatter)
}
}
}
}
}
}动态配置 FetchRequest
如果需要根据用户输入动态改变查询条件,可以将 FetchRequest 封装在一个独立的视图中,并通过 init 方法初始化它。
struct FilteredList: View {
@FetchRequest var fetchRequest: FetchedResults<Item>
init(filter: String) {
_fetchRequest = FetchRequest<Item>(
sortDescriptors: [],
predicate: NSPredicate(format: "name CONTAINS[c] %@", filter)
)
}
var body: some View {
List(fetchRequest, id: \.self) { item in
Text(item.name ?? "Unknown")
}
}
}总结
- AppStorage: 适用于全局的用户偏好设置,底层基于 UserDefaults。
- SceneStorage: 适用于特定场景的 UI 状态恢复,如多窗口应用中的独立状态。
- Core Data: 适用于复杂的数据模型和大量数据的持久化,SwiftUI 提供了
@FetchRequest等工具简化集成。
上次更新于