gpt4 book ai didi

ios - 使用 Swift 5.1 Property Wrapper 似乎会破坏 SwiftUI 更新。已知问题?

转载 作者:行者123 更新时间:2023-11-28 23:24:19 26 4
gpt4 key购买 nike

这是一个令人头疼的问题:在 ObservableObject 属性上实现一个简单的包装器会否定 SwiftUI 更新。

属性包装器的目的是为 UserDefaults 提供 getter/setter。属性包装器工作正常。但它扼杀了 SwiftUI 的更新。

我尝试过的事情:

-除了我的自定义包装器外,还添加了@Published 包装器。但 Swift 目前不支持可组合包装器(例如,一次多个属性包装器)。

-手动添加 PassthoughSubject 发布者,以复制@Published 功能。

后者也不修复属性值更改时的 View 更新。

我发现的唯一解决方法是放弃属性包装器。我最终不得不在两个地方设置状态,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()
}

}

最佳答案

你可能需要在两个不同的区域中分离@publish 和@persist 属性。虽然现在不支持可组合的属性包装器,但它们的链在大多数情况下仍然有效。

                    @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 = ""
}

}
}

}

关于ios - 使用 Swift 5.1 Property Wrapper 似乎会破坏 SwiftUI 更新。已知问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59092948/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com