引用实例方法需要等效(SWIFT)

Referencing instance method requires equivalency (SWIFT)

我正在尝试利用 SwiftUI 和 Combine 来存储我的应用程序的用户默认设置。查看其他几篇文章中的建议,我已经更新了我的代码,如下所示。但是,我现在收到 "Referencing instance method 'send()' on 'Subject' requires the types 'Setup' and 'Void' be equivalent" 的错误。有人建议我在 PassthroughSubject 中将 "Setup" 更改为 void,但是这会在应用程序启动时造成严重崩溃 - “致命错误:未找到 Setup.Type 类型的可观察对象。”

我有点不知所措...欢迎任何指点。

    ==============  DataStoreClass ============

import SwiftUI
import Foundation
import Combine

class Setup: ObservableObject {

    private var notificationSubscription: AnyCancellable?

    let objectWillChange = PassthroughSubject<Setup,Never>()

    @UserDefault(key: "keyValueBool", defaultValue: false)
    var somevalueBool: Bool {
        didSet{
            objectWillChange.send()  // <====== Referencing instance method 'send()' on 'Subject' requires the types 'Setup' and 'Void' be equivalent
        }
    }
    init() {

        notificationSubscription = NotificationCenter.default.publisher(for: UserDefaults.didChangeNotification).sink { _ in
                   self.objectWillChange.send()
        }
    }
}


============= property wrapper ===========
import Foundation

@propertyWrapper
struct UserDefault<T> {
    let key: String
    let defaultValue: T

    var wrappedValue: T {
        get {
            UserDefaults(suiteName: "group.com.my.app")!.value(forKey: key) as? T ?? defaultValue
        } set {
            UserDefaults(suiteName: "group.com.my.app")!.set(newValue, forKey: key)
        }
    }
}

send方法要求你传递主题的输入类型,否则失败完成。所以你的 send 行应该通过 Setup;

objectWillChange.send(self)

也就是说,在大多数 SwiftUI 代码中,PassthroughSubject<Void, Never>(这样 send() 不需要参数)。目前尚不清楚您所描述的崩溃的根源是什么;我们需要查看崩溃中涉及的代码才能对其进行调试。到目前为止我还没有复制它。

SwiftUI 不使用 PassthroughSubject,它使用 ObservableObjectPublisher。我很确定那是 PassthroughSubject<Void, Never> 的别名,但我不确定。 ObservableObject 协议为您定义了正确的 objectWillChange,因此您能做的最好的事情就是删除您的定义。

发布者是 objectWillChange,顾名思义,它应该在 willSet 而不是 didSet 中发送,我认为这并不重要,但 Apple 从 didSetwillSet,我猜他们有充分的理由。

错误是因为您已将 Output 类型声明为 Setup,但您正在使用 Void.

调用 objectWillChange

所以你必须将 self 传递给 objectWillChange:

self.objectWillChange.send(self)

需要注意的重要一点是,您应该调用 objectWillChange 而不是 didSet,而是 willSet:

var somevalueBool: Bool {
    willSet{
        objectWillChange.send(self
    }
}

您从未设置过 somevalueBool,所以无论如何都不会调用这段代码。

您的设置大致如下所示:

class Setup: ObservableObject {

    private var notificationSubscription: AnyCancellable?

    public let objectWillChange = PassthroughSubject<Setup,Never>()

    @UserDefault(key: "keyValueBool", defaultValue: false)
    var somevalueBool: Bool

    init() {
        notificationSubscription = NotificationCenter.default.publisher(for: UserDefaults.didChangeNotification).sink { _ in
                   self.objectWillChange.send(self)
        }
    }
}