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

Posted

技术标签:

【中文标题】引用实例方法需要等效性 (SWIFT)【英文标题】:Referencing instance method requires equivalency (SWIFT) 【发布时间】:2019-09-29 20:51:37 【问题描述】:

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

【问题讨论】:

我不是最好的组合编码器,但根据您对 &lt;Setup,Never&gt; 的定义,您告诉编译器在您的 send 中您将传递一个 Setup 实例,如 - I想想 - ``objectWillChange.send([在此处插入您的设置实例])`。我只是没有在你的代码中看到这个“设置实例”到底是什么。 【参考方案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)
        
    

【讨论】:

谢谢,这似乎已经解决了可能的主要问题.. 它仍然不像我想的那样工作,因为我更改值的 SwiftUI 代码似乎没有“触发” willSet()代码。【参考方案2】:

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

objectWillChange.send(self)

也就是说,在大多数 SwiftUI 代码中,PassthroughSubject&lt;Void, Never&gt;(因此 send() 不需要参数)。目前尚不清楚您所描述的崩溃原因是什么;我们需要查看崩溃中涉及的代码来调试它。到目前为止我还没有复制它。

【讨论】:

【参考方案3】:

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

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

【讨论】:

以上是关于引用实例方法需要等效性 (SWIFT)的主要内容,如果未能解决你的问题,请参考以下文章

Swift 中的 async/await ——代码实例详解

尝试更改对象属性并保持反应性。属性或方法“vm”未在实例上定义,但在渲染期间被引用

sizeof() 等效于引用类型?

JAVA笔记---面向过程与面向对象;类,对象;实例变量,引用;构造方法;

swift class type isa-swizzling

Vue警告:属性或方法“item”未在实例上定义,但在渲染期间被引用