SwiftUI:如何使用UserDefaults持久化@Published变量?
我想要一个@Published变量被持久化,这样每次我重新启动我的应用程序时它都是一样的 我想在一个变量上同时使用@UserDefault和@Published属性包装器。例如,我需要一个“@PublishedUserDefault var isLogedIn” 我有以下财产说唱歌手SwiftUI:如何使用UserDefaults持久化@Published变量?,swiftui,swift5,xcode11,Swiftui,Swift5,Xcode11,我想要一个@Published变量被持久化,这样每次我重新启动我的应用程序时它都是一样的 我想在一个变量上同时使用@UserDefault和@Published属性包装器。例如,我需要一个“@PublishedUserDefault var isLogedIn” 我有以下财产说唱歌手 import Foundation @propertyWrapper struct UserDefault<T> { let key: String let defaultValue:
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)
}
}
}
我的观点课
struct HomeView : View {
@EnvironmentObject var settings: Settings
var body: some View {
VStack {
if settings.isLogedIn {
Text("Loged in")
} else{
Text("Not Loged in")
}
}
}
}
有没有一种方法可以创建一个同时覆盖持久化和发布的属性包装器?您当前无法将
@UserDefault
包装在@Published
周围,因为当前不允许这样做
实现@PublishedUserDefault
的方法是将objectWillChange
传递到包装器中,并在设置变量之前调用它。private var cancelables=[String:anycancelables]()
已发布的扩展{
init(wrappedValue-defaultValue:Value,key:String){
让value=UserDefaults.standard.object(forKey:key)作为?value??defaultValue
self.init(initialValue:value)
可取消项[key]=projectedValue.sink{val in
UserDefaults.standard.set(val,forKey:key)
}
}
}
类设置:ObserveObject{
@已发布(键:“isLogedIn”)变量isLogedIn=false
...
}
样本:
所有
Codable
类型的版本签出应该可以组成一个新的属性包装:
这项提案的第一次修订没有包括组成部分,
因为可以手动组合属性包装器类型。例如
组合@A@B可以实现为AB包装器:
@propertyWrapper
结构AB{
私有var存储
var wrappedValue:Value{
获取{storage.wrappedValue.wrappedValue}
设置{storage.wrappedValue.wrappedValue=newValue}
}
}
这种方法的主要好处是它的可预测性
AB决定如何最好地实现A和B的组合,命名它
并提供正确的API和其应用程序的文档
语义学。另一方面,必须手动写出每个
合成是很多样板,特别是对于一个
主要的卖点是消除了陈词滥调。也是
不幸的是,当我尝试时,不得不为每一篇作文发明名字
通过@A@B组合A和B,我如何知道去寻找
手动合成的属性包装类型AB?或者应该是这样
文学学士
Ref:要持久保存数据,可以使用
@AppStorage
属性包装器。
但是,如果不使用@Published
,您的ObservableObject
将不再发布有关更改数据的新闻。要解决此问题,只需从属性的willSet
observer调用objectWillChange.send()
class Settings: ObservableObject {
@AppStorage("Example") var example: Bool = false {
willSet {
// Call objectWillChange manually since @AppStorage is not published
objectWillChange.send()
}
}
}
在示例
struct字段中
。它将字符串
作为参数。您必须传入objectWillChange
。发布的@Published
的唯一特殊之处在于它调用objectWillChange.send()
在适当的时候。@Fabian我在下面发布了我的解决方案,避免了传入objectWillChange
的麻烦,而定制PropertyRapper
的意思是使用一个定制init,它只使用现有的存储,并通过更改时的接收器在设置时存储。我没想到。:-)我的解决方案更麻烦,在使用PropertyRapper之前,您必须在init()
内部设置objectWillChange
。谢谢您,这使它更简单了^ ^谢谢@victor!应该可以双向设置,以便用户默认值更改更新值。我对您的答案有一个小问题,在已发布的扩展中添加单个Userdefaults是否会导致应用程序使所有项目在任何地方都可以访问?如果我也这么做,但使用Keychain,会对性能产生影响吗?
@propertyWrapper
struct AB<Value> {
private var storage: A<B<Value>>
var wrappedValue: Value {
get { storage.wrappedValue.wrappedValue }
set { storage.wrappedValue.wrappedValue = newValue }
}
}
struct HomeView : View {
@StateObject var auth = Auth()
@AppStorage("username") var username: String = "Anonymous"
var body: some View {
VStack {
if username != "Anonymous" {
Text("Logged in")
} else{
Text("Not Logged in")
}
}
.onAppear(){
auth.login()
}
}
}
import SwiftUI
import Combine
class Auth: ObservableObject {
func login(params:[String:String]) {
Webservice().login(params: params) { response in
if let myresponse = response {
UserDefaults.standard.set(myresponse.login, forKey: "username")`
}
}
}
}
class Settings: ObservableObject {
@AppStorage("Example") var example: Bool = false {
willSet {
// Call objectWillChange manually since @AppStorage is not published
objectWillChange.send()
}
}
}