如何使用 2 Swift 协议创建观察者模式,其中两个关联类型必须相同?

How do I make an Observer pattern with 2 Swift protocols, where the two associatedtypes must be the same?

我正在尝试使用 SE-0142 (Associated Type Constraints) 创建一个具有 2 个协议的观察者模式,IsObserver(如客户端)和 HasObservers(如服务器),其中有一个shared DataType 表示被观察事物的类型。

我需要符合 HasObservers 的对象能够成为结构或 class,并且我希望 IsObserver 有意限制为 class(想要,但不需要)。

我不擅长使用泛型...几个小时后我走到了这一步,编译器错误出现在下面的内嵌注释中。我被困住了,不知道下一步该去哪里,我不确定这种方法是否可行或合理。非常感谢所有帮助!

import Foundation

protocol IsObserver: class {
    associatedtype DataType
    func dataDidUpdate(_ data: [DataType])
}

struct Observation<T: IsObserver> {
    weak var observer: T?
}


protocol HasObservers {
    associatedtype DataType : IsObserver where DataType.DataType == DataType
    static var observations: [ObjectIdentifier : Observation<IsObserver>] { get set } // ERROR: "Value of protocol type 'IsObserver' cannot conform to 'IsObserver'; only struct/enum/class types can conform to protocols"
    static func tellObserversDataDidUpdate(_ data: [DataType])
}

extension HasObservers {
    static func tellObserversDataDidUpdate(_ data: [DataType]) {
        for (id, observation) in observations {
            guard let observer = observation.observer else {
                observations.removeValue(forKey: id)
                continue
            }
            observer.dataDidUpdate(data)
        }
    }

    static func addObserver<T: IsObserver>(_ observer: T) {
        let id = ObjectIdentifier(observer)
        let ob = Observation.init(observer: observer)
        observations[id] = ob
    }

    static func removeObserver<T: IsObserver>(_ observer: T) {
        let id = ObjectIdentifier(observer)
        observations.removeValue(forKey: id)
    }
}

UPDATE:好的,终于到了。比我想象的要难,需要类型擦除。在这个要点中有两个版本:第一个版本是根据原始问题使用关联类型协议的版本。虽然它是有限的——作为观察者的对象只能观察一种类型。所以我做了另一个可以有多种类型但不使用 associatetype 协议的变体,所以观察者必须手动检查类型。

https://gist.github.com/xaphod/4f8a6402429759b6b3fd8ea2d8ea53c4

我将稍微简化您的用例(忽略观察),希望能理解这个概念。

HasObservers 基本上有 2 种关联类型 - DataTypeIsObserver 类型,然后您将限制 IsObserver 类型具有正确的 DataType

protocol IsObserver {
  associatedtype DataType
  func dataDidUpdate(_ data: [DataType])
}

protocol HasObservers {
  associatedtype DataType
  associatedtype ObserverType: IsObserver where ObserverType.DataType == DataType

  static func addObserver(_ observer: ObserverType)
  static func tellObserversDataDidUpdate(_ data: [DataType])

  // ..
}