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

时间:2019-09-29 20:51:37

标签: swift swiftui combine

我正在尝试利用SwiftUI和Combine来存储我的应用程序的用户默认值。查看其他一些帖子中的建议,如下所示,我已经更新了代码。但是,我现在收到“在'Subject'上引用实例方法'send()'要求类型'Setup'和'Void'等效的错误”的错误。已经建议我在PassthroughSubject中将“安装程序”更改为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)
        }
    }
}

3 个答案:

答案 0 :(得分:1)

该错误来自以下事实:您已将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)
        }
    }
}

答案 1 :(得分:0)

send方法要求您传递主题的输入类型或失败完成。因此,您的send行应通过Setup;

objectWillChange.send(self)

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

答案 2 :(得分:0)

SwiftUI不使用PassthroughSubject,而是使用ObservableObjectPublisher。我很确定这是PassthroughSubject<Void, Never>的别名,但我不确定。 ObservableObject协议为您定义了正确的objectWillChange,因此最好的操作是删除定义。

发布者是objectWillChange,顾名思义,发布者应该以{{1​​}}而不是willSet的形式发送,我认为这没什么大不了,但是Apple从{{1 }}到didSet,我猜测他们有充分的理由。