How do I use UserDefaults with SwiftUI?

谁说胖子不能爱 提交于 2019-12-01 06:40:59

First, create a property wrapper that will allow us to easily make the link between your Settings class and 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)
        }
    }
}

Then, create a data store that holds your settings:

import Combine
import SwiftUI

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

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

Now, in your view, access your settings:

import SwiftUI

struct SettingsView : View {
    @EnvironmentObject var dataStore: DataStore

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

The approach from caram is in general ok but there are so many problems with the code that SmushyTaco did not get it work. Bellow you will find an "Out of the Box" working solution.

// 1. UserDefaults propertyWrapper

import Foundation

@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 class

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

    @UserDefault("ShowOnStart", defaultValue: false)
    var showOnStart: Bool {
        didSet {
            didChange.send()
        }
    }
}

// 3. SwiftUI view

struct SettingsView : View {
    @ObjectBinding var settings = UserSettings()

    var body: some View {
        VStack {
            Toggle(isOn: $settings.showOnStart) {
                Text("Show welcome text")
            }
            if settings.showOnStart{
                Text("Welcome")
            }
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!