下面是一个简单的抓取器:在ObservableObject属性上实现一个简单的包装器会否定SwiftUI更新。
属性包装器的目的是为UserDefaults提供一个getter / setter。属性包装器工作正常。但它扼杀了SwiftUI的更新。
我尝试过的事情:
除了我的自定义包装之外,-Adding @已发布的包装器。但是Swift目前不支持可组合的包装器(例如,一次不止一个属性包装器)。
-Manually添加了一个PassthoughSubject发布服务器,以复制@已发布的功能。
后者也不修复属性值更改的视图更新。
我找到的唯一解决办法是放弃属性包装器。最后,我不得不在两个位置设置状态: 1)在@Published属性上设置状态,2)在UserDefaults中设置状态。这看起来很笨重,而且反重复状态的模式。
这是个众所周知的问题吗?
完整编译代码在https://github.com/taskcruncher/propertyWrapperSwiftUIBug.git。“works”分支是我不得不复制状态的地方。下面是“坏掉的”分支,其中使用自定义的属性包装器会中断SwiftUI更新。
ContentView.swift
import Combine
//https://www.avanderlee.com/swift/property-wrappers/
@propertyWrapper
struct PersistInUserDefaults<T> {
let key: String
let defaultValue: T
var wrappedValue: T {
get {
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
}
class AppleUser: ObservableObject {
static var shared = AppleUser()
let subject = PassthroughSubject<String, Never>()
@PersistInUserDefaults(key: "appleID", defaultValue: "") var appleID: String {willSet {
subject.send(newValue) // problem here: does not trigger UI updates
}}
}
struct ContentView: View {
@ObservedObject var appleUser: AppleUser
var body: some View {
return VStack {
Text(appleUser.appleID)
}.onAppear{
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.appleUser.appleID = "Sven"
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) {
self.appleUser.appleID = "Olaf"
}//update not reflected in UI
DispatchQueue.main.asyncAfter(deadline: .now() + 3.5) {
self.appleUser.appleID = "Anna"
}//update not reflected in UI
}
}
}SceneDelegate.swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let contentView = ContentView(appleUser: AppleUser.shared)
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}发布于 2019-11-28 19:59:39
Yo可能需要将两个不同区域的“发布”和“持久化”属性分开。虽然现在不支持可组合的属性包装器,但它们的链在大多数时候仍然工作。
@propertyWrapper
struct PersistInUserDefaults<T> {
let key: String
let defaultValue: T
var wrappedValue: T {
get {
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
}
struct PersistInUserDefaults_Wrapper {
@PersistInUserDefaults(key: "appleID", defaultValue: "") var value
}
class AppleUser: ObservableObject {
static var shared = AppleUser()
@Published var appleID = PersistInUserDefaults_Wrapper()
}
struct ContentMMMMSSSView: View {
@ObservedObject var appleUser: AppleUser
var body: some View {
return VStack {
Text(appleUser.appleID.value)
}.onAppear{
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.appleUser.appleID.value = "Leonard"
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) {
self.appleUser.appleID.value = "Bill"
}//
DispatchQueue.main.asyncAfter(deadline: .now() + 3.5) {
self.appleUser.appleID.value = ""
}
}
}
}https://stackoverflow.com/questions/59092948
复制相似问题