如何在 SwiftUI 中使用 UserDefaults 保存选择器数据?

How I can save picker data with UserDefaults in SwiftUI?

我试图在 SwiftUI 的 UserDefault 中保存用户选择器组件的选择,但与简单的切换相反,我被阻止了。

我的看法:

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())
    }
  }
}

设置商店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()
    }
  }
}

UserDefault 扩展名:

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) }
  }
}

所以我的 UserDefaults 扩展中有一些错误。我不知道如何保存多个字符串选项以及如何显示默认选项。

您必须保存枚举的原始值,即字符串。

getter 有点广泛但安全

// Vibration intensity
static var vibrationIntensity: VibrationType {
   get {
      if let vibrationRawValue = UserDefaults.standard.string(forKey: Keys.vibrationIntensity),
           let type = VibrationType(rawValue: vibrationRawValue) {
         return type
      } else {
         return VibrationType(rawValue: "Normal")!
      }
   }
   set { UserDefaults.standard.set(newValue.rawValue, forKey: Keys.vibrationIntensity) }
}

在下面找到固定代码...使用 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)
        }
    }
}

从 iOS 14,使用 onChange()

@State private var index = UserDefaults.standard.integer(forKey: "YourKey")
Picker(...)
   .onChange(of: index) { newValue in
      // Run code to save
      UserDefaults.standard.set(newValue, forKey: "YourKey")
   }