swiftswiftuipicker

SwiftUI / Can't save Picker timer


I can't save the selected timer value after leaving View.

Briefly: the user enters the screen, selects the timer time, clicks save, the selected value is saved in UserDefaults. Then the person leaves the screen (via the cross at the top). When he returns to the timer view - there should be the last set value from UserDefaults.

Timer model code:

import SwiftUI
import Combine

class TimerSettings: ObservableObject {
    
    @Published var selectedTime: Int?
    
    init(initialSelectedTime: Int?) {
        self.selectedTime = initialSelectedTime
    }
    func saveSettings(time: Int, forKey: String) {
        UserDefaults.standard.set(time, forKey: forKey)
        print(time)
    }
    func loadSettings(forKey: String) -> Int? {
        if let savedSettings = UserDefaults.standard.object(forKey: forKey) as? Int {
            selectedTime = savedSettings
            return savedSettings
        } else {
            selectedTime = nil
            return nil
        }
    }
}

TimerView code:

import SwiftUI

struct TimerView: View {

    @StateObject var timerSettings = TimerSettings(initialSelectedTime: nil)

    @State var selectedTime = 3
    
    var body: some View {
            VStack {
                Text("Change time:")
                    .foregroundStyle(Color(.black).opacity(0.8))
                Picker("Timer", selection: $selectedTime) {
                    ForEach(1..<31, id: \.self) {
                        Text("\($0) min").tag($0)
                    }
                }.pickerStyle(WheelPickerStyle())
                    .frame(width: 300, height: 300)
                Button("Save") {
                
                    timerSettings.saveSettings(time: selectedTime, forKey: "timerSettings")
                    
                }
                .font(.title)
                .foregroundColor(.blue)
                .padding(.bottom, 100)
                .onAppear {
                    timerSettings.loadSettings(forKey: "timerSettings")!
                }
            }
            .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()
                }
            }
        }
    }

#Preview {
    TimerView()
}

Solution

  • I got help with a solution:

    So, Timer settings without any changes:

    import SwiftUI
    import Combine
    
    class TimerSettings: ObservableObject {
    
        @Published var selectedTime: Int?
    
        init(initialSelectedTime: Int?) {
            self.selectedTime = initialSelectedTime
        }
        //униварсальная функция сохранения
        func saveSettings(time: Int, forKey: String) {
            UserDefaults.standard.set(time, forKey: forKey)
            print(time)
        }
        //универсальная функция загрузки
        func loadSettings(forKey: String) -> Int? {
            if let savedSettings = UserDefaults.standard.object(forKey: forKey) as? Int {
                selectedTime = savedSettings
                return savedSettings
            } else {
                selectedTime = nil
                return nil
            }
        }
    }
    

    And only one thing on View in .onAppear:

     import SwiftUI
        
        struct TimerView: View {
        
            @State var timerSettings = TimerSettings(initialSelectedTime: nil)
        
            @State var selectedTime = 0
            @State var mainTime = 3
        
            var body: some View {
                    VStack {
                        Text("Настройте таймер игры:")
                            .foregroundStyle(Color(.black).opacity(0.8))
                        Picker("Время таймера", selection: $mainTime) {
                            ForEach(1..<31, id: \.self) {
                                Text("\($0) мин").tag($0)
                            }
                        }.pickerStyle(WheelPickerStyle())
                            .frame(width: 300, height: 300)
                        Button("Сохранить") {
                            selectedTime = mainTime
                            timerSettings.saveSettings(time: selectedTime, forKey: "timerSettings")
                        }
                        .font(.title)
                        .foregroundColor(.blue)
                        .padding(.bottom, 100)
                    }
                    .onAppear {
                        mainTime = timerSettings.loadSettings(forKey: "timerSettings")!
                    }
                    .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()
                        }
                    }
                }
            }
        
        #Preview {
            TimerView()
        }