将自定义属性包装器与@Published相结合

Mil*_*dek 8 swift combine property-wrapper

我希望将自定义属性包装器应用于已包装在 中的变量@Published,将它们像
(A) @Custom @Published var myVar
(B) @Published @Custom var myVar
一样嵌套 (注意包装器的应用顺序)。

在(A)的情况下,我收到错误

'wrappedValue' is unavailable: @Published is only available on properties of classes

对于(B)

error: key path value type 'Int' cannot be converted to contextual type 'Updating<Int>'

两者都不是特别有帮助。有什么想法如何让它发挥作用吗?

最小代码示例

import Combine

class A {
    @Updating @Published var b: Int
    
    init(b: Int) {
        self.b = b
    }
}

@propertyWrapper struct Updating<T> {
    var wrappedValue: T {
        didSet {
            print("Update: \(wrappedValue)")
        }
    }
}

let a = A(b: 1)
let cancellable = a.$b.sink {
    print("Published: \($0)")
}
a.b = 2
// Expected output:
// ==> Published: 1
// ==> Published: 2
// ==> Update: 2
Run Code Online (Sandbox Code Playgroud)

Sim*_*one 2

您提供的任何选项都不能应用于使自定义属性包装器的行为像用 @Published 标记的那样(A 和 B)

真正的问题是,我如何观察属性/状态更新变化?

  1. 使用@Published包装器,自动处理状态更新

  2. 通过实施来手动跟踪状态更新

    willSet {objectWillChange.send()}

考虑到选项 1 无法工作,因为您无法应用 2 个属性包装器,因此您可以进行手动状态更新跟踪。为了实现这一点,您需要使您的类符合 ObservableObject 协议。

class A: ObservableObject {
    @Updating var b: Int{
       willSet {objectWillChange.send()}
    }
    
    init(b: Int) {
        self.b = b
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,只要 var b 发生更改,您的视图就可以刷新,同时您的 @Updating 包装器可以完全正常工作。