Swift结构体中使用@AppStorage实现独立按钮状态持久化遇阻
解决多按钮独立禁用状态持久化问题
问题核心
@AppStorage的键必须是编译时常量,无法用实例属性(比如你的level)作为动态键,所以直接在ButtonData里写@AppStorage(level)会报错。下面提供两种可行的解决思路:
方案1:手动操作UserDefaults
放弃@AppStorage包装器,直接通过UserDefaults读写状态,这样就能用level作为动态键:
struct ButtonData { let id = UUID() let level: String let bgColor: String let image: String // 读取/写入禁用状态 var isDisabled: Bool { get { UserDefaults.standard.bool(forKey: level) } set { UserDefaults.standard.set(newValue, forKey: level) } } }
使用时直接修改isDisabled即可,UserDefaults会自动完成持久化,重启APP后状态依然保留。
方案2:用ObservableObject统一管理状态
如果按钮数量较多或需要更复杂的状态操作,可以用ObservableObject封装所有按钮的禁用状态,同样基于UserDefaults实现持久化:
class ButtonStateManager: ObservableObject { // 从UserDefaults加载初始状态,修改时自动同步到本地 @Published private var disabledStates: [String: Bool] { didSet { UserDefaults.standard.set(disabledStates, forKey: "buttonDisabledStates") } } init() { self.disabledStates = UserDefaults.standard.dictionary(forKey: "buttonDisabledStates") as? [String: Bool] ?? [:] } // 获取指定level的禁用状态 func isDisabled(for level: String) -> Bool { disabledStates[level] ?? false } // 设置指定level的禁用状态 func setDisabled(_ disabled: Bool, for level: String) { disabledStates[level] = disabled objectWillChange.send() } } // 简化ButtonData,状态交由Manager管理 struct ButtonData { let id = UUID() let level: String let bgColor: String let image: String }
在View中使用时,需要注入状态管理器:
struct ContentView: View { @StateObject private var stateManager = ButtonStateManager() let buttons: [ButtonData] = [ ButtonData(level: "level1", bgColor: "red", image: "star"), ButtonData(level: "level2", bgColor: "blue", image: "moon") ] var body: some View { VStack { ForEach(buttons) { button in Button(action: { stateManager.setDisabled(true, for: button.level) }) { Image(systemName: button.image) .padding() .background(Color(button.bgColor)) } .disabled(stateManager.isDisabled(for: button.level)) } } } }
这个方案的优势是状态集中管理,方便后续扩展(比如批量重置状态、监听全局状态变化等)。
内容的提问来源于stack exchange,提问作者Uday Agarwal
相关产品推荐
相关产品推荐

