当泛型值受 AnyObject 约束时,无法将其转换为 AnyObject

时间:2021-02-17 17:18:32

标签: swift

错误是 Cannot convert value of type '(O?, ObservedType) -> Void' to expected argument type '(AnyObject?, ObservedType) -> Void,但我觉得这很奇怪,因为 O 被限制为 AnyObject

对于上下文,我正在创建自己的 Observable 类,但这个问题实际上是关于上面的特定错误消息,而不是我如何使用任何其他第三方框架来使用 observable。也就是说,在这种情况下我如何正确地转换我的完成处理程序。

public class Observable<ObservedType> {
    struct Observer<ObservedType> {
        weak var observer: AnyObject?
        let completion: (AnyObject?, ObservedType) -> Void
    }

    private var observers: [Observer<ObservedType>]
    
    public var value: ObservedType? {
        didSet {
            if let _ = value {
                notifyObservers()
            }
        }
    }
    
    public init(_ value: ObservedType? = nil) {
        self.value = value
        observers = []
    }
    
    
    public func observe<O: AnyObject>(forward object: O?, completion: @escaping (O?, ObservedType) -> Void) {
        observers.append(Observer(observer: object, completion: completion)) // error here
        if let value = value {
            completion(object, value)
        }
    }
    
    private func notifyObservers() {
        for observer in observers {
            if let value = value {
                DispatchQueue.main.async { observer.completion(nil, value) }
            }
        }
    }
}

在这种情况下是否可以强制转换我的完成处理程序,或者以某种方式等同于 OAnyObject

1 个答案:

答案 0 :(得分:1)

根据你的类型,我可以将任何我想要的对象传递给Observer.completion的第一个参数。但是您分配给 .completion 的函数只能接受某些特定类型 O

您必须将 completion 更改为 (AnyObject?, ObservedType) -> Void

public func observe<O: AnyObject>(forward object: O?, completion: @escaping (AnyObject?, ObservedType) -> Void) {
                                                                             ^^^^^^^^^^

你传递的函数将不得不处理它可以传递任何东西的事实。我怀疑这会破坏你的整个系统。但我不相信这种 Observable 风格会奏效,因为正是这些类型的问题。

直接将 Observer 存储在 Observable 中真的没有什么好方法。您目前没有使用它,但我假设您想要它用于删除观察者之类的事情。有办法做到这一点,但你不能存储观察者本身。你可以返回一个唯一的标识符(例如 UUID),或者你可以使用 ObjectIdentifiers 或者你可以传回观察者必须调用的“删除这个项目”闭包。但是您通常不想直接存储观察者(绝对不是作为 AnyObject)。

我建议为此使用Combine,因为它就是为此而设计的。或者,如果您需要支持较旧的 iOS 版本,请参阅 this experiment 了解实现此功能的方法,或参阅 this experiment 了解更接近您在此处尝试执行的操作的简化版本。