web-dev-qa-db-ja.com

SwiftUIでUserDefaultsを使用するにはどうすればよいですか?

struct ContentView: View {
@State var settingsConfiguration: Settings
    struct Settings {
        var passwordLength: Double = 20
        var moreSpecialCharacters: Bool = false
        var specialCharacters: Bool = false
        var lowercaseLetters: Bool = true
        var uppercaseLetters: Bool = true
        var numbers: Bool = true
        var space: Bool = false
    }
  var body: some View {
    VStack {
                HStack {
                    Text("Password Length: \(Int(settingsConfiguration.passwordLength))")
                    Spacer()
                    Slider(value: $settingsConfiguration.passwordLength, from: 1, through: 512)
                }
                Toggle(isOn: $settingsConfiguration.moreSpecialCharacters) {
                    Text("More Special Characters")
                }
                Toggle(isOn: $settingsConfiguration.specialCharacters) {
                    Text("Special Characters")
                }
                Toggle(isOn: $settingsConfiguration.space) {
                    Text("Spaces")
                }
                Toggle(isOn: $settingsConfiguration.lowercaseLetters) {
                    Text("Lowercase Letters")
                }
                Toggle(isOn: $settingsConfiguration.uppercaseLetters) {
                    Text("Uppercase Letters")
                }
                Toggle(isOn: $settingsConfiguration.numbers) {
                    Text("Numbers")
                }
                Spacer()
                }
                .padding(.all)
                .frame(width: 500, height: 500)
  }
}

だから私はここにこのすべてのコードを持っており、スイッチが変更されたときやスライダーがスライドされたときに設定を保存し、アプリの起動時にこのすべてのデータを取得するためにUserDefaultsを使用したいのですが、SwiftUIでUserDefaultsを使用する方法がわかりません(または一般にUserDefaults、私はそれを調べ始めたばかりなので、SwiftUIアプリで使用できますが、表示されるすべての例はUIKitのためのものであり、SwiftUIでそれらを実装しようとすると、大量のエラーが発生します)。

17
SmushyTaco

Caramからのアプローチは一般的に大丈夫ですが、コードに非常に多くの問題があるため、SmushyTacoはそれを機能させませんでした。怒鳴るあなたは「箱から出して」実用的な解決策を見つけるでしょう。

1. UserDefaults propertyWrapper

import Foundation
import Combine

@propertyWrapper
struct UserDefault<T> {
    let key: String
    let defaultValue: T

    init(_ key: String, defaultValue: T) {
        self.key = key
        self.defaultValue = defaultValue
    }

    var wrappedValue: T {
        get {
            return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
        }
        set {
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }
}

2. UserSettingsクラス

final class UserSettings: ObservableObject {

    let objectWillChange = PassthroughSubject<Void, Never>()

    @UserDefault("ShowOnStart", defaultValue: true)
    var showOnStart: Bool {
        willSet {
            objectWillChange.send()
        }
    }
}

3. SwiftUIビュー

struct ContentView: View {

@ObservedObject var settings = UserSettings()

var body: some View {
    VStack {
        Toggle(isOn: $settings.showOnStart) {
            Text("Show welcome text")
        }
        if settings.showOnStart{
            Text("Welcome")
        }
    }
}
26
Marc T.

以下のコードは、Mohammad Azamの優れたソリューションを このビデオ に適合させています。

import SwiftUI

struct ContentView: View {
    @ObservedObject var userDefaultsManager = UserDefaultsManager()

    var body: some View {
        VStack {
            Toggle(isOn: self.$userDefaultsManager.firstToggle) {
                Text("First Toggle")
            }

            Toggle(isOn: self.$userDefaultsManager.secondToggle) {
                Text("Second Toggle")
            }
        }
    }
}

class UserDefaultsManager: ObservableObject {
    @Published var firstToggle: Bool = UserDefaults.standard.bool(forKey: "firstToggle") {
        didSet { UserDefaults.standard.set(self.firstToggle, forKey: "firstToggle") }
    }

    @Published var secondToggle: Bool = UserDefaults.standard.bool(forKey: "secondToggle") {
        didSet { UserDefaults.standard.set(self.secondToggle, forKey: "secondToggle") }
    }
}
8
protasm

まず、設定クラスとUserDefaultsの間のリンクを簡単に作成できるようにするプロパティラッパーを作成します。

import Foundation

@propertyWrapper
struct UserDefault<Value: Codable> {    
    let key: String
    let defaultValue: Value

    var value: Value {
        get {
            let data = UserDefaults.standard.data(forKey: key)
            let value = data.flatMap { try? JSONDecoder().decode(Value.self, from: $0) }
            return value ?? defaultValue
        }
        set {
            let data = try? JSONEncoder().encode(newValue)
            UserDefaults.standard.set(data, forKey: key)
        }
    }
}

次に、設定を保持するデータストアを作成します。

import Combine
import SwiftUI

final class DataStore: BindableObject {
    let didChange = PassthroughSubject<DataStore, Never>()

    @UserDefault(key: "Settings", defaultValue: [])
    var settings: [Settings] {
        didSet {
            didChange.send(self)
        }
    }
}

次に、ビューで設定にアクセスします。

import SwiftUI

struct SettingsView : View {
    @EnvironmentObject var dataStore: DataStore

    var body: some View {
        Toggle(isOn: $settings.space) {
            Text("\(settings.space)")
        }
    }
}
5
caram