这是一组通用协议,旨在为基本的观察者模式实现提供一个简单的基础设施。
该框架不处理观察者和被观察者之间的消息传递或通信管理。它只是为它们提供相互跟踪的基础设施。
有一些回调,明确与聚合管理相关,但除此之外,它只是一个提供可靠的关系图管理的工具。
由具体的实现来处理如何使用这些信息。
该框架基于协议,而不是类或结构体。其中一些协议要求必须将其实现为类。协议默认实现被大量用于提供基础设施。
从本质上讲,任何观察者模式的实现实际上只是一个关系图。观察者订阅被观察者。被观察者使用订阅作为单向广播媒介。
管理订阅和关系对于该模式至关重要。如果我们不能信任我们的订阅列表,那么建立在其之上的所有东西都将面临风险。
Apple 在其许多 Cocoa 基础设施中使用 委托模式。这是一种出色而简单的模式,具有以下特性:
观察者(至少,我实现的方式)有不同的方面:
管理订阅列表和关系是观察者模式的一个非常基本的部分,并且需要非常可靠。这就是开发此工具的原因。
我们甚至不应该考虑这个问题。
仓库的 URI 是:
一旦你将该包包含在你的项目中(如果你想了解更多关于 SPM 的信息,你可能想 查看这个系列),你需要包含该库。它将是一个静态(构建时)库。
import RVS_GeneralObserver
你可以通过将以下行添加到你的 Cartfile 中来包含该库:
github "RiftValleySoftware/RVS_GeneralObserver"
你可能应该直接包含 Carthage/Checkouts/RVS_GeneralObserver/Sources/RVS_GeneralObserver/RVS_GeneralObserver_Protocols.swift
文件,而不是构建一个库。
如果你想将该项目作为一个子模块包含,只需使用上面的 URI 之一(在 Swift Package Manager 部分)。最好直接从子模块包含 Sources/RVS_GeneralObserver/RVS_GeneralObserver_Protocols.swift
文件(无需模块导入)。
如果你只想下载并包含该文件,那么只需要处理一个文件。Sources/RVS_GeneralObserver/RVS_GeneralObserver_Protocols.swift
文件。
只需下载并包含该文件。无需导入模块。
完成之后,你可以通过遵循 RVS_GeneralObservableProtocol
协议,使一个类(它需要是一个类)成为被观察者。
你需要在你的实现中创建两个存储属性(以下示例来自 单元测试):
class BaseObservable: RVS_GeneralObservableProtocol {
/* ############################################################## */
/**
The required UUID. It is set up with an initializer, and left alone.
*/
let uuid = UUID()
/* ############################################################## */
/**
This is the required observers Array.
*/
var observers: [RVS_GeneralObserverProtocol] = []
uuid
属性是一个“设置并忘记”的属性。只需完全按照上面的方法做,之后就不用担心它了。
observers
数组也是一个你不太可能直接使用的数组(但你可能会转换它)。它是跟踪订阅者的地方。这是你的被观察者将如何找到广播目标。通常,你可能会将其转换为更具体的类的数组,如下所示:
var castArray: [MySpecificSubscriberThatConformsToRVS_GeneralObserverProtocol] { observers as? [MySpecificSubscriberThatConformsToRVS_GeneralObserverProtocol] ?? [] }
我们有两种类型的观察者。一种是“通用”的,可以应用于 struct
和 class
,它不跟踪观察者订阅的被观察者;另一种是仅限 class
的变体,它跟踪观察者的订阅。
这些示例也来自 单元测试。
struct BaseObserver: RVS_GeneralObserverProtocol {
/* ############################################################## */
/**
The required UUID. It is set up with an initializer, and left alone.
*/
let uuid = UUID()
class SubTrackerObserver: RVS_GeneralObserverSubTrackerProtocol {
/* ############################################################## */
/**
The required UUID. It is set up with an initializer, and left alone.
*/
let uuid = UUID()
/* ############################################################## */
/**
This is where we will track our subscriptions.
*/
var subscriptions: [RVS_GeneralObservableProtocol] = []
由于协议默认实现使用引用数组,因此这应该是一个 class
。
订阅一个被观察者就像调用它的 subscribe()
方法一样简单,并提供观察者。
let subscribedObserver = observableInstance.subscribe(observerInstance)
如果订阅成功,则响应是 observerInstance
。这允许该方法被链式调用。如果观察者已经被订阅,则可能为 nil。
取消订阅完全相同,只是这次我们调用 unsubscribe()
方法。
let unsubscribedObserver = observableInstance.unsubscribe(observerInstance)
还有 unsubscribeAll()
方法,用于 被观察者 和 订阅跟踪观察者。
调用这些方法将从一个被观察者实例中删除所有观察者,或者从一个观察者实例中删除所有被观察者。
协议中没有任何必需的回调,但有一些非常基本的可选回调。
观察者协议在确认订阅时进行回调
func subscribedTo(_ observable: RVS_GeneralObservableProtocol)
以及在确认取消订阅时进行回调
func unsubscribedFrom(_ observable: RVS_GeneralObservableProtocol)
订阅跟踪协议有 几个内部方法,不应该被遵循协议的实例使用。
被观察者协议有一个可选回调
func observer(_ observer: RVS_GeneralObserverProtocol, didSubscribe: Bool)
当一个观察者订阅或取消订阅时(第二个参数表示这一点)会调用此回调。
一旦你设置好 class
(或 struct
),你就可以使用 observers
属性(被观察者)或 subscriptions
属性(观察者协议的订阅跟踪变体)来访问和与各种目标交互,并根据需要进行类型转换。
所有协议都有一个 amISubscribed()
布尔方法,你可以传入一个观察者(或被观察者)实例进行测试,以查看一个观察者是否订阅了一个被观察者。