Search code examples
swiftuipickeruserdefaults

How I can save picker data with UserDefaults in SwiftUI?


I'm trying to save the user choice from picker component in UserDefault in SwiftUI but in contrary of a simple toggle, I'am blocked.

My View:

import SwiftUI

enum VibrationType: String, CaseIterable {
  case low = "Faible"
  case normal = "Normal"
  case hight = "Fort"
}

struct CompassSettings: View {

  @ObservedObject var settingsStore: SettingsStore = SettingsStore()

  @State var vibrationIntensityIndex = 1

  var body: some View {
    VStack {
      Toggle(isOn: $settingsStore.vibrationActivate) {
        Text("Activer la vibration")
          .font(.system(size: 18))
          .foregroundColor(Color("TextDark"))
      }
      .padding(.top, 6)

      Picker("Intesité de la vibration", selection: self.$settingsStore.vibrationIntensity) {
        ForEach(0..<self.vibrationIntensity.count) { intensity in
          Text(self.vibrationIntensity[intensity]).tag(intensity)
        }
      }
      .pickerStyle(SegmentedPickerStyle())
    }
  }
}

SettingsStore class:

import SwiftUI
import Combine

final class SettingsStore: ObservableObject {

  let vibrationIsActivate = PassthroughSubject<Void, Never>()
  let intensityOfVibration = PassthroughSubject<Void, Never>()

  // Vibration
  var vibrationActivate: Bool = UserDefaults.vibrationActivated {
    willSet {
      UserDefaults.vibrationActivated = newValue
      vibrationIsActivate.send()
    }
  }

  // Vibration intensity
  var vibrationIntensity: VibrationType = .normal {
    willSet {
      UserDefaults.vibrationIntensity = newValue
      print(UserDefaults.vibrationIntensity)
      intensityOfVibration.send()
    }
  }
}

The UserDefault extension:

extension UserDefaults {

  private struct Keys {
    static let vibrationActivated = "vibrationActivated"
    static let vibrationIntensity = "vibrationIntensity"
  }

  // Vibration
  static var vibrationActivated: Bool {
    get { return UserDefaults.standard.bool(forKey: Keys.vibrationActivated) }
    set { UserDefaults.standard.set(newValue, forKey: Keys.vibrationActivated) }
  }

  // Vibration intensity
   static var vibrationIntensity: VibrationType {
    get { return UserDefaults.standard.object(forKey: Keys.vibrationIntensity) as! 
    VibrationType ?? "normal" }
    set { UserDefaults.standard.set(newValue, forKey: Keys.vibrationIntensity) }
  }
}

So I have some errors in my UserDefaults extension. I don't know how I can save multiple string choices and how I can display a default choice.


Solution

  • Find below fixed code... tested with Xcode 11.2 / iOS 13.2.

    enum VibrationType: String, CaseIterable {
        case low = "Faible"
        case normal = "Normal"
        case hight = "Fort"
    }
    
    struct CompassSettings: View {
    
        @ObservedObject var settingsStore: SettingsStore = SettingsStore()
    
        @State var vibrationIntensityIndex = 1
    
        @State var vibrationIntensity: [VibrationType] = [.low, .normal, .hight]
        var body: some View {
            VStack {
                Toggle(isOn: $settingsStore.vibrationActivate) {
                    Text("Activer la vibration")
                        .font(.system(size: 18))
                        .foregroundColor(Color("TextDark"))
                }
                .padding(.top, 6)
    
                Picker("Intesité de la vibration", selection: self.$settingsStore.vibrationIntensity) {
                    ForEach(self.vibrationIntensity, id: \.self) { intensity in
                        Text(intensity.rawValue).tag(intensity)
                    }
                }
                .pickerStyle(SegmentedPickerStyle())
            }
        }
    }
    
    final class SettingsStore: ObservableObject {
    
        let vibrationIsActivate = PassthroughSubject<Void, Never>()
        let intensityOfVibration = PassthroughSubject<Void, Never>()
    
        // Vibration
        var vibrationActivate: Bool = UserDefaults.vibrationActivated {
            willSet {
                UserDefaults.vibrationActivated = newValue
                vibrationIsActivate.send()
            }
        }
    
        // Vibration intensity
        var vibrationIntensity: VibrationType = UserDefaults.vibrationIntensity {
            willSet {
                UserDefaults.vibrationIntensity = newValue
                print(UserDefaults.vibrationIntensity)
                intensityOfVibration.send()
            }
        }
    }
    
    extension UserDefaults {
    
        private struct Keys {
            static let vibrationActivated = "vibrationActivated"
            static let vibrationIntensity = "vibrationIntensity"
        }
    
        // Vibration
        static var vibrationActivated: Bool {
            get { return UserDefaults.standard.bool(forKey: Keys.vibrationActivated) }
            set { UserDefaults.standard.set(newValue, forKey: Keys.vibrationActivated) }
        }
    
        // Vibration intensity
        static var vibrationIntensity: VibrationType {
            get {
                if let value = UserDefaults.standard.object(forKey: Keys.vibrationIntensity) as? String {
                    return VibrationType(rawValue: value)!
                }
                else {
                    return .normal
                }
            }
            set {
                UserDefaults.standard.set(newValue.rawValue, forKey: Keys.vibrationIntensity)
            }
        }
    }