首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用SWIFT5.1属性包装器似乎会破坏SwiftUI更新。已知的问题?

使用SWIFT5.1属性包装器似乎会破坏SwiftUI更新。已知的问题?
EN

Stack Overflow用户
提问于 2019-11-28 16:20:35
回答 1查看 865关注 0票数 0

下面是一个简单的抓取器:在ObservableObject属性上实现一个简单的包装器会否定SwiftUI更新。

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

我尝试过的事情:

除了我的自定义包装之外,-Adding @已发布的包装器。但是Swift目前不支持可组合的包装器(例如,一次不止一个属性包装器)。

-Manually添加了一个PassthoughSubject发布服务器,以复制@已发布的功能。

后者也不修复属性值更改的视图更新。

我找到的唯一解决办法是放弃属性包装器。最后,我不得不在两个位置设置状态: 1)在@Published属性上设置状态,2)在UserDefaults中设置状态。这看起来很笨重,而且反重复状态的模式。

这是个众所周知的问题吗?

完整编译代码在https://github.com/taskcruncher/propertyWrapperSwiftUIBug.git。“works”分支是我不得不复制状态的地方。下面是“坏掉的”分支,其中使用自定义的属性包装器会中断SwiftUI更新。

ContentView.swift

代码语言:javascript
复制
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

代码语言:javascript
复制
    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()
        }

    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-11-28 19:59:39

Yo可能需要将两个不同区域的“发布”和“持久化”属性分开。虽然现在不支持可组合的属性包装器,但它们的链在大多数时候仍然工作。

代码语言:javascript
复制
                    @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  = ""
                                  }

                    }
                }

            }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59092948

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档