如何在SwiftUI中使用UserDefaults? struct ContentView:View{ @状态变量设置配置:设置 结构设置{ var passwordLength:Double=20 var moreSpecialCharacters:Bool=false 变量specialCharacters:Bool=false var lowercaseLetters:Bool=true var大写字母:Bool=true 变量编号:Bool=true 变量空间:Bool=false } var body:一些观点{ VStack{ HStack{ 文本(“密码长度:\(Int(settingsConfiguration.passwordLength))) 垫片() 滑块(值:$settingsConfiguration.passwordLength,从:1到:512) } 切换(isOn:$settingsConfiguration.moreSpecialCharacters){ 文本(“更多特殊字符”) } 切换(isOn:$settingsConfiguration.specialCharacters){ 文本(“特殊字符”) } 切换(isOn:$settingsConfiguration.space){ 文本(“空格”) } 切换(isOn:$settingsConfiguration.Lowersceletters){ 文本(“小写字母”) } 切换(isOn:$settingsConfiguration.大写字母){ 文本(“大写字母”) } 切换(isOn:$settingsConfiguration.Number){ 文本(“数字”) } 垫片() } .padding(.all) .框架(宽:500,高:500) } }

如何在SwiftUI中使用UserDefaults? struct ContentView:View{ @状态变量设置配置:设置 结构设置{ var passwordLength:Double=20 var moreSpecialCharacters:Bool=false 变量specialCharacters:Bool=false var lowercaseLetters:Bool=true var大写字母:Bool=true 变量编号:Bool=true 变量空间:Bool=false } var body:一些观点{ VStack{ HStack{ 文本(“密码长度:\(Int(settingsConfiguration.passwordLength))) 垫片() 滑块(值:$settingsConfiguration.passwordLength,从:1到:512) } 切换(isOn:$settingsConfiguration.moreSpecialCharacters){ 文本(“更多特殊字符”) } 切换(isOn:$settingsConfiguration.specialCharacters){ 文本(“特殊字符”) } 切换(isOn:$settingsConfiguration.space){ 文本(“空格”) } 切换(isOn:$settingsConfiguration.Lowersceletters){ 文本(“小写字母”) } 切换(isOn:$settingsConfiguration.大写字母){ 文本(“大写字母”) } 切换(isOn:$settingsConfiguration.Number){ 文本(“数字”) } 垫片() } .padding(.all) .框架(宽:500,高:500) } },swift,nsuserdefaults,swiftui,Swift,Nsuserdefaults,Swiftui,因此,我这里有所有这些代码,我想在开关更改或滑动滑块时使用UserDefaults保存设置,并在应用程序启动时检索所有这些数据,但我不知道如何在SwiftUI中使用UserDefaults(或者说用户默认值一般来说,我刚刚开始研究它,以便将其用于我的SwiftUI应用程序,但我看到的所有示例都是针对UIKit的,当我尝试在SwiftUI中实现它们时,我遇到了大量错误).首先,创建一个属性包装器,使我们能够轻松地在设置类和用户默认值之间建立链接: import Foundation @prope

因此,我这里有所有这些代码,我想在开关更改或滑动滑块时使用UserDefaults保存设置,并在应用程序启动时检索所有这些数据,但我不知道如何在SwiftUI中使用UserDefaults(或者说用户默认值一般来说,我刚刚开始研究它,以便将其用于我的SwiftUI应用程序,但我看到的所有示例都是针对UIKit的,当我尝试在SwiftUI中实现它们时,我遇到了大量错误).

首先,创建一个属性包装器,使我们能够轻松地在设置类和用户默认值之间建立链接:

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

caram的方法大体上是可以的,但是代码有太多的问题,SmushyTaco没有让它工作

1.UserDefaults PropertyRapper
以下代码适用于Mohammad Azam的优秀解决方案:


如果您要持久化一个一次性结构,以致属性包装太过简单,则可以将其编码为JSON。解码时,对于无数据的情况,请使用空的
Data
实例

final类UserData:observeObject{
@已发布的var配置文件:配置文件?=try?JSONDecoder().decode(profile.self,from:UserDefaults.standard.data(forKey:“profile”)?data()){
didSet{UserDefaults.standard.set(try?JSONEncoder().encode(profile),forKey:“profile”)}
}
}
从Xcode 12.0(iOS 14.0)开始,您可以对以下类型使用
@AppStorage
属性包装器:
Bool、Int、Double、String、URL
Data
。 以下是存储字符串值的用法示例:

struct ContentView: View {
    
    static let userNameKey = "user_name"
    
    @AppStorage(Self.userNameKey) var userName: String = "Unnamed"
    
    var body: some View {
        VStack {
            Text(userName)
            
            Button("Change automatically ") {
                userName = "Ivor"
            }
            
            Button("Change manually") {
                UserDefaults.standard.setValue("John", forKey: Self.userNameKey)
            }
        }
    }
}
在这里,您将使用默认值声明
userName
属性,默认值不会进入
UserDefaults
本身。当您首次对其进行变异时,应用程序会将该值写入
UserDefaults
并用新值自动更新视图

如果需要,还可以通过如下参数设置自定义
UserDefaults
提供程序:

@AppStorage(Self.userNameKey, store: UserDefaults.shared) var userName: String = "Mike"

注意:如果该值将在应用程序外部更改(比如手动打开plist文件并更改值),则View将不会收到该更新


另外,
View
上还有一个新的扩展,它添加了
func-defaultAppStorage(u-store:UserDefaults)->some View
允许更改视图所用的存储。如果有很多
@AppStorage
属性,并且为每个属性设置自定义存储很麻烦,那么这会很有帮助。

另一个很好的解决方案是使用
@propertyrapper
的非官方静态下标API,而不是
wrappedValue
简化了许多代码。定义如下:

@propertyWrapper
结构用户默认值{
让键:字符串
让defaultValue:Value
init(wrappedValue:Value,\ key:String){
self.key=key
self.defaultValue=wrappedValue
}
var wrappedValue:Value{
获取{fatalError(“称为wrappedValue getter”)}
set{fatalError(“称为wrappedValue setter”)}
}
静态下标(
_enclosingInstance实例:首选项,
包装的wrappedKeyPath:ReferenceWritableKeyPath,
存储密钥路径:引用可写密钥路径
)->价值{
得到{
let wrapper=instance[keyPath:storageKeyPath]
将instance.userDefaults.value(forKey:wrapper.key)作为?value??wrapper.defaultValue返回
}
设置{
instance.objectWillChange.send()
让key=instance[keyPath:storageKeyPath].key
instance.userDefaults.set(newValue,forKey:key)
}
}
}
然后,您可以这样定义设置对象:

@AppStorage(Self.userNameKey, store: UserDefaults.shared) var userName: String = "Mike"
最终类设置:ObserveObject{
let userDefaults:userDefaults
init(默认值:UserDefaults=.standard){
userDefaults=默认值
}
@UserDefaults(“yourKey”)变量yourSetting:SettingType
...
}
但是,要注意这种实现。用户倾向于将其所有应用程序设置放在此类对象中的一个对象中,并在依赖于一个设置的每个视图中使用它。这可能导致由于在多个视图中有太多不必要的
objectWillChange
通知而导致的速度减慢。 你绝对应该通过打破僵局来分离关注点
final class UserSettings: ObservableObject {

    let objectWillChange = PassthroughSubject<Void, Never>()

    @UserDefault("ShowOnStart", defaultValue: true)
    var showOnStart: Bool {
        willSet {
            objectWillChange.send()
        }
    }
}
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")
        }
    }
}
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") }
    }
}
struct ContentView: View {
    
    static let userNameKey = "user_name"
    
    @AppStorage(Self.userNameKey) var userName: String = "Unnamed"
    
    var body: some View {
        VStack {
            Text(userName)
            
            Button("Change automatically ") {
                userName = "Ivor"
            }
            
            Button("Change manually") {
                UserDefaults.standard.setValue("John", forKey: Self.userNameKey)
            }
        }
    }
}
@AppStorage(Self.userNameKey, store: UserDefaults.shared) var userName: String = "Mike"
extension UserDefaults {
    static var shared: UserDefaults {
        let combined = UserDefaults.standard
        combined.addSuite(named: "group.myapp.app")
        return combined
    }
}