You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI问题:Picker计时器选中值离开视图后无法保存

问题解决:计时器视图无法加载上次保存的Picker选中值

核心问题分析

  1. Picker绑定独立于模型:当前Picker绑定的是视图本地的@State selectedTime变量,而非TimerSettings模型中的@Published selectedTime。模型加载保存值后,不会同步到这个本地变量,导致Picker始终显示初始值3。
  2. 可选类型不匹配:模型中selectedTime是可选类型,但Picker的标签都是非可选整数,容易引发状态不一致。
  3. 强制解包风险: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 08:35:10