SwiftUI问题:Picker计时器选中值离开视图后无法保存
问题解决:计时器视图无法加载上次保存的Picker选中值
核心问题分析
- Picker绑定独立于模型:当前Picker绑定的是视图本地的
@State selectedTime变量,而非TimerSettings模型中的@Published selectedTime。模型加载保存值后,不会同步到这个本地变量,导致Picker始终显示初始值3。 - 可选类型不匹配:模型中
selectedTime是可选类型,但Picker的标签都是非可选整数,容易引发状态不一致。 - 强制解包风险:
onAppear中强制解包loadSettings的返回值,无保存值时会崩溃。
修复步骤及代码
1. 重构TimerSettings模型
简化逻辑,将selectedTime改为非可选类型,初始化时直接加载保存值(无保存值则用默认3):
import SwiftUI import Combine class TimerSettings: ObservableObject { @Published var selectedTime: Int init() { // 从UserDefaults加载值,无值则设为默认3 let savedTime = UserDefaults.standard.integer(forKey: "timerSettings") self.selectedTime = (1...30).contains(savedTime) ? savedTime : 3 } func saveSettings() { UserDefaults.standard.set(selectedTime, forKey: "timerSettings") print("Saved time: \(selectedTime)") } // 手动重新加载(用于onAppear确保最新值) func reloadSettings() { let savedTime = UserDefaults.standard.integer(forKey: "timerSettings") self.selectedTime = (1...30).contains(savedTime) ? savedTime : 3 } }
2. 修改TimerView视图
移除本地@State变量,直接绑定Picker到模型的selectedTime,并调整保存逻辑:
import SwiftUI struct TimerView: View { @StateObject var timerSettings = TimerSettings() var body: some View { VStack { Text("Change time:") .foregroundStyle(Color(.black).opacity(0.8)) Picker("Timer", selection: $timerSettings.selectedTime) { ForEach(1..<31, id: \.self) { Text("\($0) min").tag($0) } } .pickerStyle(WheelPickerStyle()) .frame(width: 300, height: 300) Button("Save") { timerSettings.saveSettings() } .font(.title) .foregroundColor(.blue) .padding(.bottom, 100) } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color(#colorLiteral(red:0.8980392157, green: 0.9333333333, blue: 1, alpha: 1))) .navigationBarBackButtonHidden(true) .toolbar { ToolbarItem(placement: .navigationBarLeading) { CustomBackButtonView() } } .onAppear { // 确保每次进入视图都加载最新保存值 timerSettings.reloadSettings() } } } #Preview { TimerView() }
关键改进说明
- Picker与模型双向绑定:Picker直接绑定到
$timerSettings.selectedTime,模型值变化会自动同步到Picker,反之亦然。 - 安全的默认值处理:初始化模型时检查保存值是否在有效范围(1-30),无效则用默认3,避免空值或非法值。
- 移除冗余状态:不再需要本地
@State selectedTime,所有状态统一由模型管理,保证一致性。 - 避免强制解包:
reloadSettings中无需解包,直接通过范围检查处理默认值,消除崩溃风险。
内容的提问来源于stack exchange,提问作者deshollow
相关产品推荐
相关产品推荐

