如何在Mac应用中使用@AppStorage存储SwiftUI List的选中状态
解决方案
问题根因
@AppStorage 默认仅支持 Bool、Int、Double、String、URL、Data 这类基础类型的持久化存储,无法直接识别遵从 RawRepresentable 协议的自定义枚举类型,因此你原本直接将枚举类型绑定到 @AppStorage 的写法无法正常读写存储值。
方案1:中转基础类型做转换(兼容性最高)
不需要额外扩展,直接通过中间存储字符串、自定义绑定做类型转换即可,适配所有支持 @AppStorage 的系统版本:
只需修改 ContentView 的代码如下即可:
struct ContentView: View { // 存储枚举的原始字符串值 @AppStorage("selection") private var storedSelection: String = Fruit.apple.rawValue // 自定义绑定实现字符串和枚举的双向转换 private var selection: Binding<Fruit> { Binding( get: { Fruit(rawValue: storedSelection) ?? .apple }, set: { storedSelection = $0.rawValue } ) } var body: some View { NavigationView { Sidebar(selection: selection) DetailView(selection: selection.wrappedValue) } .frame(width: 500, height: 300) } }
方案2:扩展@AppStorage支持RawRepresentable类型(写法最简洁)
如果项目部署目标为 macOS 11+,可以扩展 @AppStorage 让它原生支持所有RawValue为@AppStorage兼容类型的枚举,添加扩展后原有代码无需修改即可正常运行:
- 先添加全局扩展:
extension AppStorage where Value: RawRepresentable, Value.RawValue == String { init(wrappedValue: Value, _ key: String, store: UserDefaults? = nil) { self.init(key, store: store) self.wrappedValue = wrappedValue } }
- 原有代码的
@AppStorage("selection") private var selection: Fruit = .apple可以直接正常使用。
验证说明
两种方案都可以实现选中状态的持久化,应用重启后会自动读取存储值恢复上次选中的条目,不需要额外编写状态恢复的逻辑。
内容的提问来源于stack exchange,提问作者wigging
相关产品推荐
相关产品推荐

