【问题标题】:Observer pattern in swift with default implementationsswift中的观察者模式与默认实现
【发布时间】:2018-08-05 21:33:58
【问题描述】:

这是我的代码:

public protocol Subjectable: class {
    associatedtype T

    var observers: [T] { get set }

    func addObserver(_ observer: T)
    func removeObserver(_ observer: T)
    func removeAllObservers()
}

public extension Subjectable {
    func removeAllObservers() {
        observers.removeAll()
    }

    func removeObserver(_ observer: T) {
        observers = observers.filter { $0 !== observer.self } // error
    }

    func addObserver(_ observer: T) {
        observers.append(observer.self)
    }
}

我说错了

二元运算符“!==”不能应用于“_”类型的操作数和 '自我.T'

我不确定它想告诉我什么。我可以使用.self 后缀毫无问题地添加观察者。但是,我可以通过在associatedtype T 后面添加: AnyObject 来消除编译错误,但是我无法创建一个协议和一个可以编译的类(我收到错误说协议不符合AnyObject,不管我是否在协议后面加上: AnyObject

有什么方法可以创建一个带有协议和默认实现的观察者模式,这些协议和默认实现可以编译并且我可以使用(创建协议和类:))。

编辑:观察者也是一个协议,而不是一个类。

编辑 2:这行得通(但我必须一直重新实现 addObserver 方法)

public protocol MyProtocol: AnyObject {}

public class MyClass: Subjectable {
    public var observers = [MyProtocol]()

    public func removeObserver(_ observer: MyProtocol) {
        observers = observers.filter { $0 === observer }
    }
}

【问题讨论】:

  • 你的意思是observers = observers.filter { $0 !== observer }
  • @Sweeper 我想使用 associatedtype 作为协议,而不是作为一个类。你知道结果如何吗?

标签: swift protocols


【解决方案1】:

您认为T 必须是一个类 (AnyObject) 是正确的。您无需在此处的任何地方使用.self

public protocol Subjectable: class {
    associatedtype T: AnyObject // Require T to be a class type for !==
    // ...
}

public extension Subjectable {
    // ...
    func removeObserver(_ observer: T) {
        observers = observers.filter { $0 !== observer }  // Remove .self
    }

    func addObserver(_ observer: T) {
        observers.append(observer) // Remove .self
    }
}

然后您可以使用默认实现来实现它:

class O {}

class X: Subjectable {
    var observers: [O] = []
}

【讨论】:

  • 嘿,Rob,也许我的问题不够清楚,无法说明我使用关联类型 T 作为协议(所以不是像 O 这样的类)。 T 永远是一个协议。确实,这会编译,但我不能使用 T 作为协议,因为我尝试这样做时会出错(细节在问题中)
  • 观察者不能是协议。协议不是类,您需要 !== 的类。要求类型成为类的协议仍然不是类。它仍然是一个协议。在 Swift 中,协议不符合它们自己。您需要重新设计它以不要求 T 成为协议或不使用 !==(例如使用 Equatable 而不是 AnyObject)。
  • 请注意,由于Self 的要求,在这里使用Equatable 几乎肯定会爆炸。您需要仔细考虑为什么要在此处使用协议,并了解如何删除它。协议极大地复杂化了 Swift。除非它们具有非常强大的目的,否则不要注入它们。
  • 是的,但它不能是一个协议,也不能做你想做的事情。您无法在依赖于您声称是类的另一个协议的协议内访问===。是的,Swift 有一些可以工作的特殊情况(例如具体类型中的协议对象数组),但它们不是通用的(即,这并不意味着您可以可靠地使用协议中的协议对象数组) .您正在推动协议超越它们在 Swift 中的工作位置。在今天的 Swift 中,在协议之上构建复杂系统非常脆弱,并且充满了奇怪的极端情况。
猜你喜欢
  • 2016-02-20
  • 2011-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-07
  • 2021-07-10
  • 2017-06-11
  • 2013-12-09
相关资源
最近更新 更多