将代码的不同单元解耦对项目(们)的长期可维护性贡献巨大。 虽然观察者模式通过仅要求观察者遵循共同约定的接口(在 Swift 中为协议)来提供一定程度的解耦,但我们可以使用事件驱动模式更进一步。
使用事件驱动系统,各个代码单元之间绝对没有直接引用。 相反,每个独立的代码单元都会发出和监听事件(如果适用)。 事件只是一个包含不可变信息的结构化对象。 然后,每个代码单元可以根据收到的事件进行操作,并在该特定代码单元的上下文中执行任何必要的操作。
Event Driven Swift 是一个极其强大的库,专门用于在 Swift 语言中驱动您的事件驱动应用程序。
传统的软件设计原则要求通信对象直接相互引用,而事件驱动的设计模式消除了这种需求。
理解此库及其支持示例/文档中使用的术语将极大地帮助您立即利用这些工具来生成极其强大、高性能、完全解耦且易于维护的事件驱动解决方案。
事件 只是一个不可变的信息负载,可用于驱动逻辑和行为。
将事件 视为类似于操作触发器。 为了响应收到已知类型的事件,一个不同的代码单元将根据在该事件的有效负载中收到的信息执行适当的操作。
在 EventDrivenSwift
中,我们通常将事件 定义为符合 Eventable
协议的 struct
。
这是一个简单的例子
struct TemperatureEvent: Eventable {
var temperatureInCelsius: Float
}
请注意,上面的示例 TemperatureEvent
是最基本的事件 示例,因为它仅包含一条信息。 实际上,您的事件 可以封装尽可能多的信息,只要它对于单个有凝聚力的操作触发器是合乎逻辑的。
重要提示: 事件 应该绝不包括任何引用类型的值(例如 class
实例)。 事件 需要是不可变的,这意味着在它们被分发后,它们的任何值都不可能更改。
事件队列 是 Eventable
对象的一个连续集合 (Array
),只要队列 不为空,它将自动被处理。 队列 总是按照先进先出(或 FiFo)的顺序处理。
请注意,分发到队列 的事件 将始终在分发到堆栈 的事件 之后处理。
事件堆栈 实际上与事件队列 相同,只是它以相反的顺序处理:后进先出(或 LiFo)
请注意,分发到堆栈 的事件 将始终在分发到队列 的事件 之前处理。
事件 可以以以下优先级 之一分发到队列 或堆栈: .highest
将首先处理 .high
将第二个处理 .normal
将第三个处理 .low
将第四个处理 .lowest
将最后处理
这意味着我们可以在分发点强制执行一定程度的执行顺序。
分发 是一个类似于广播 的术语。 当我们分发 一个事件 时,这意味着我们将该信息发送到每个正在监听该事件类型 的 EventThread
(请参阅下一节)。
一旦事件 被分发,就无法取消或修改。 这是设计使然。 可以把它想象成“你不能在你说了之后就不说它”。
事件 可以从代码中的任何位置分发,而不管哪个线程 正在调用它。 从这个意义上讲,事件 非常像一个发送后忘记 的过程。
EventThread
是一个 class
,它继承了此库提供的名为 EventThread
的基本类型。
在表面之下,EventThread
继承自 Thread
,并且实际上被称为 Persistent Thread
。 这意味着 Thread
通常会存在于您的特定应用程序需要它的时间那么长,甚至存在于您的应用程序的整个生命周期内。
与大多数线程不同,EventThread
专门构建为以尽可能低的系统资源占用运行。 当没有事件 等待您的 EventThread
处理时,该线程将完全不消耗 CPU 时间,并且实际上不消耗任何电量。
一旦您的 EventThread
收到它已订阅 的 Eventable
类型的事件,它将自动唤醒 并处理其各自的队列 和堆栈 中任何等待的事件。
注意: 任意数量的 EventThread
可以接收相同的事件。 这意味着您可以出于任何数量的目的,以任何数量的方式,以任何数量的结果来处理同一个事件。
当您定义 EventThread
后代时,您将实现一个名为 registerEventListeners
的函数。 在此函数中(每次初始化 EventThread
后代类型的实例时都会自动调用该函数),您将注册您的 EventThread
感兴趣的 Eventable
类型; 并为每个类型定义一个合适的处理程序(或回调)方法,以便在这些事件 发生时处理它们。
您将在本文档后面的 用法 部分看到详细的示例,但这里要理解的关键是,对于您的 EventThread
有兴趣处理的每种 Eventable
类型,您将能够在一行代码中注册该事件 类型的事件处理程序。
这使得管理和维护每个 EventThread
已被实现来处理的事件订阅 变得非常容易。
EventDrivenSwift
专门设计用于在分发 事件 时以及处理 事件 时提供尽可能好的性能平衡。
考虑到这一点,EventDrivenSwift
默认提供了一个中央事件分发处理程序。 无论何时您通过队列 或堆栈 分发 一个事件,它都会立即在中央事件分发处理程序 中排队,然后它将通过其自己的线程 分发 到所有已注册的 EventThread
。
这意味着在指示事件 分发 和在调用线程的执行中继续之间几乎没有等待时间。
尽管以这种方式使用中介处理程序,但事件 的分发 和每个 EventThread
对该事件 的处理 之间的时间非常短! 这使得 EventDrivenSwift
对于性能关键型应用程序(包括视频游戏)非常有用!
EventDrivenSwift
构建在我们的 Observable
库之上,并且 EventThread
继承自 ObservableThread
,这意味着它支持完整的观察者模式 行为以及事件驱动 行为。
简而言之:您可以在代码中任何需要的地方观察 EventThread
,包括从 SwiftUI 视图中。
这意味着您的应用程序可以动态更新您的视图以响应接收和处理的事件,使您的应用程序真正且完全多线程,而无需您生成代码来处理线程间通信。
EventDrivenSwift
也构建在我们的 ThreadSafeSwift
库之上,并且 EventDrivenSwift
中每种类型的每个公共方法和成员都专门设计为线程安全。
强烈建议您使用 EventDrivenSwift
的自己的实现严格遵守最佳线程安全标准。 话虽如此,除非您定义一个专门用于在 UI 上显示信息的公开可访问的 var
或 func
,否则大多数使用纯事件驱动方法构建的后端实现都不需要过多地关注线程安全。
选择 File
-> Swift Packages
-> Add Package Dependency
并输入 https://github.com/Flowduino/EventDrivenSwift.git
您可以在您自己的 Package 的 Package.swift
文件中使用 EventDrivenSwift
作为 Package 依赖项
let package = Package(
//...
dependencies: [
.package(
url: "https://github.com/Flowduino/EventDrivenSwift.git",
.upToNextMajor(from: "5.0.0")
),
],
//...
)
从那里,在任何需要它的 *您的* 包的目标中,将 EventDrivenSwift
称为“目标依赖项”。
targets: [
.target(
name: "YourLibrary",
dependencies: [
"EventDrivenSwift",
],
//...
),
//...
]
然后您可以在任何需要它的代码中执行 import EventDrivenSwift
。
所以,既然我们已经了解了 EventDrivenSwift
是什么,它做什么,并且我们已经涵盖了许多重要的术语,让我们来看看我们实际上如何使用它。
您可以通过简单地从 Eventable
继承来将几乎任何 struct
类型转换为事件 类型
struct TemperatureEvent: Eventable {
var temperatureInCelsius: Float
}
它真的就是这么简单!
现在我们有了一个定义的事件 类型,让我们看看我们将如何分发 这种类型的事件
let temperatureEvent = TemperatureEvent(temperatureInCelsius: 23.25)
以上创建了我们的 TemperatureEvent
事件 类型的实例。 如果我们想通过具有 .normal
优先级 的队列 来分发它,我们可以像这样轻松地做到这一点
temperatureEvent.queue()
我们还可以自定义优先级
temperatureEvent.queue(priority: .highest)
以上将通过具有 .highest
优先级 的堆栈 分发事件。
通过堆栈 分发时,同样有效
temperatureEvent.stack()
以上将再次使用 .normal
优先级...
temperatureEvent.stack(priority: .highest)
以上将使用 .highest
优先级。
4.2.0 版本将计划分发 引入到库中
temperatureEvent.scheduleQueue(at: DispatchTime.now() + TimeInterval().advanced(by: 4), priority: .highest)
以上将在 4 秒后通过具有最高优先级 的队列 分发 temperatureEvent
temperatureEvent.scheduleStack(at: DispatchTime.now() + TimeInterval().advanced(by: 4), priority: .highest)
以上将在 4 秒后通过具有最高优先级 的堆栈 分发 temperatureEvent
当您的用例需要在事件 的组合与其分发 以进行处理之间有固定或计算的延迟时,计划事件分发 是一大优势。
所以,我们有一个事件 类型,并且我们能够通过队列 或堆栈 以我们想要的任何优先级 来分发 它。 现在我们需要一种方法来接收我们的 *
TemperatureEvent以便我们可以用它们做一些事情。 一种方法是定义一个
EventThread来监听和处理我们的
TemperatureEvent`。
class TemperatureProcessor: EventThread {
/// Register our Event Listeners for this EventThread
override func registerEventListeners() {
addEventCallback(onTemperatureEvent, forEventType: TemperatureEvent.self)
}
/// Define our Callback Function to process received TemperatureEvent Events
func onTemperatureEvent(_ event: TemperatureEvent, _ priority: EventPriority, _ dispatchTime: DispatchTime) {
}
}
在我们深入研究 onTemperatureEvent
的实现之前,它基本上可以对 TemperatureEvent
中提供的数据做任何我们想做的事情,让我们花点时间来了解上面的代码中发生了什么。
首先,TemperatureProcessor
继承自 EventThread
,这是发生所有接收事件 和注册我们的监听器(或回调 或处理程序)的魔力的地方。
当创建 TemperatureProcessor
的实例时,将自动调用函数 registerEventListeners
。 在此方法中,我们调用 addEventCallback
来注册 onTemperatureEvent
,以便在每次分发 类型为 TemperatureEvent
的事件 时都会调用它。
我们的回调(或处理程序 或监听器事件)被称为 onTemperatureEvent
,我们将在其中实现要对 TemperatureEvent
执行的任何操作。
5.0.0 版本引入了新参数 dispatchTime
,它将始终提供 Event 被Dispatched 的 DispatchTime
引用。你可以使用它来确定 Delta(自 Event 被Dispatched 以来经过了多少时间),这在你执行插值和/或外推时特别有用。
现在,让我们在 onTemperatureEvent
方法中实际对我们的 TemperatureEvent
做一些事情。
/// An Enum to map a Temperature value onto a Rating
enum TemperatureRating: String {
case belowFreezing = "Below Freezing"
case freezing = "Freezing"
case reallyCold = "Really Cold"
case cold = "Cold"
case chilly = "Chilly"
case warm = "Warm"
case hot = "Hot"
case reallyHot = "Really Hot"
case boiling = "Boiling"
case aboveBoiling = "Steam"
static func fromTemperature(temperatureInCelsius: Float) -> TemperatureRating {
if temperatureInCelsius < 0 { return .belowFreezing }
else if temperatureInCelsius == 0 { return .freezing }
else if temperatureInCelsius < 5 { return .reallyCold }
else if temperatureInCelsius < 10 { return .cold }
else if temperatureInCelsius < 16 { return .chilly }
else if temperatureInCelsius < 22 { return .warm }
else if temperatureInCelsius < 25 { return .hot }
else if temperatureInCelsius < 100 { return .reallyHot }
else if temperatureInCelsius == 100 { return .boiling }
else { return .aboveBoiling }
}
}
@ThreadSafeSemaphore public var temperatureInCelsius: Float = Float.zero
@ThreadSafeSemaphore public var temperatureRating: TemperatureRating = .freezing
func onTemperatureEvent(_ event: TemperatureEvent, _ priority: EventPriority, _ dispatchTime: DispatchTime) {
temperatureInCelsius = event.temperatureInCelsius
temperatureRating = TemperatureRating.fromTemperature(event.temperatureInCelsius)
}
}
上面的代码旨在说明问题,而不是实用。 我们的 onTemperatureEvent
将 Event 封装的 temperatureInCelsius
传递给一个公共变量(然后其他代码可以根据需要读取该变量),作为 EventThread
的一部分,并且还基于 Event 中接收到的温度值预先计算 TemperatureRating
。
最终,你的代码可以使用 Event 的 Payload 数据做任何你想做的事情!
目前你唯一缺少的是如何创建 EventListner
类型的实例。 实际上,这非常简单。 以下代码可以在 Playground 中运行
let temperatureProcessor = TemperatureProcessor()
这就是创建 TemperatureProcessor
实例所需的一切。
让我们添加一行来打印 temperatureProcessor
的初始值
print("Temp in C: \(temperatureProcessor.temperatureInCelsius)")
print("Temp Rating: \(temperatureProcessor.temperatureRating)")
我们现在可以 Dispatch 一个 TemperatureEvent
以便由 temperatureProcessor
处理
TemperatureEvent(temperatureInCelsius: 25.5).queue()
因为 Events 是异步处理的,并且因为这只是一个 Playground 测试,所以让我们添加一个 1 秒的睡眠时间,以使 TemperatureProcessor
有时间接收和处理 Event。 注意: 实际上,这只需要不到 1 毫秒即可处理!
sleep(1)
现在让我们再次打印相同的值,看看它们是否已更改
print("Temp in C: \(temperatureProcessor.temperatureInCelsius)")
print("Temp Rating: \(temperatureProcessor.temperatureRating)")
现在你有一小段 Playground 代码可以直观地确认你的 Events 正在被处理。 你可以修改它以查看发生了什么。
请记住,EventThread
也是可观察的,因此我们不仅可以接收和操作 Events,还可以响应 Events 通知 Observers。
让我们看一个基于上述示例的简单示例。 我们将从定义一个 Observer Protocol 开始
protocol TemperatureProcessorObserver: AnyObject {
func onTemperatureEvent(temperatureInCelsius: Float)
}
现在让我们修改我们在上一个示例中实现的 onTemperatureEvent
方法
func onTemperatureEvent(_ event: TemperatureEvent, _ priority: EventPriority, _ dispatchTime: DispatchTime) {
temperatureInCelsius = event.temperatureInCelsius
temperatureRating = TemperatureRating.fromTemperature(event.temperatureInCelsius)
/// Notify any Observers...
withObservers { (observer: TemperatureProcessorObserver) in
observer.onTemperatureEvent(temperatureInCelsius: event.temperatureInCelsius)
}
}
现在,每次 EventThread
处理 TemperatureEvent
时,它还会通知任何直接的 Observers。
应该注意的是,此功能是对事件驱动行为的补充,因为没有“一刀切”的解决方案可以满足软件中的所有需求。 通常需要结合使用各种方法才能获得最佳结果。
通常,系统不仅消费信息,还返回信息(结果)。 这不仅在事件驱动系统中如此,而且也很容易实现。
让我们再次扩展前面的示例,这次发出一个互惠的 Event 来封装温度,以及我们响应 TemperatureEvent
计算出的 TemperatureRating
。
我们将首先定义互惠的 Event 类型
enum TemperatureRatingEvent: Eventable {
var temperatureInCelsius: Float
var temperatureRating: TemperatureRating
}
定义了 Event 类型后,我们现在可以再次扩展我们的 onTemperatureEvent
以 Dispatch 我们的互惠 TemperatureRatingEvent
func onTemperatureEvent(_ event: TemperatureEvent, _ priority: EventPriority, _ dispatchTime: DispatchTime) {
temperatureInCelsius = event.temperatureInCelsius
temperatureRating = TemperatureRating.fromTemperature(event.temperatureInCelsius)
/// Notify any Observers...
withObservers { (observer: TemperatureProcessorObserver) in
observer.onTemperatureEvent(temperatureInCelsius: event.temperatureInCelsius)
}
/// Dispatch our Reciprocal Event...
TemperatureRatingEvent(
temperatureInCelsius = temperatureInCelsius,
temperatureRating = temperatureRating
).queue()
}
如你所见,我们可以在单个操作中创建和 Dispatch 一个 Event。 这是因为 Events 应被视为“发射后不管”。 如果你希望稍后在同一操作中使用它的值,则只需在 Dispatching Method 中保留 Event 的副本即可。 否则,只需创建它并一起 Dispatch 它,如上所示。
现在我们已经完成了这些基本的使用示例,看看你是否可以生成自己的 EventThread
来处理 TemperatureRatingEvent
。 你需要实现此目的的所有内容已在本文档中演示。
2.0.0 版本引入了 UIEventThread
基类,其操作方式与 EventThread
完全相同,但值得注意的是,你注册的 Event 回调将始终在 MainActor
(或“UI 线程”)上调用。 只要必须在一个或多个 Event 回调上在 MainActor
上执行,你就可以简单地从 UIEventThread
而不是 EventThread
继承。
3.0.0 版本将 EventListener
概念引入了库。 这些是一种通用的方法(可以在你定义的任何 class
中使用),用于接收从代码中的任何位置 Dispatch 的 Events,并且使用起来需要少得多的代码。
EventListener
是一种通用方法,可以在代码中的任何位置订阅 Events,而无需定义并在 EventThread
的约束下运行。
按照设计,EventDrivenSwift
提供了一个中央事件侦听器,如果你的任何代码通过引用 Eventable
类型来为 Event 注册一个 Listener,该侦听器将自动初始化。
重要提示: EventListener
(默认情况下)将从 Listener 注册的同一线程(或 DispatchQueue
)调用关联的 Callbacks
! 这是一个非常有用的行为,因为它意味着从 MainActor
(或“UI 线程”)注册的 Listeners 将始终在该线程上执行,而无需你添加额外的开销或代码。
让我们在一些任意的 class
中注册一个简单的 Listener。 对于此示例,让我们生成一个假设的 View Model,该模型将监听 TemperatureRatingEvent
,并使拥有的 View
无效以显示新收到的值。
为了这个例子,让我们以纯 SwiftUI 的方式定义它,而不利用我们的 Observable
库
class TemperatureRatingViewModel: ObservableObject {
@Published var temperatureInCelsius: Float
@Published var temperatureRating: TemperatureRating
var listenerHandle: EventListenerHandling?
internal func onTemperatureRatingEvent(_ event: TemperatureRatingEvent, _ priority: EventPriority, _ dispatchTime: DispatchTime) {
temperatureInCelsius = event.temperatureInCelsius
temperatureRating = event.temperatureRating
}
init() {
// Let's register our Event Listener Callback!
listenerHandle = TemperatureRatingEvent.addListener(self, onTemperatureRatingEvent)
}
}
它确实是如此简单!
我们可以直接引用 Eventable
类型,并调用 addListener
方法(自动绑定到所有 Eventable
类型)来注册我们的 Listener。
在上面的示例中,只要 Reciprocal Event 名为 TemperatureRatingEvent
被 dispatched,任何 TemperatureRatingViewModel
实例的 onTemperatureRatingEvent
方法都会被调用,在该 Event 的上下文中!
不要担心管理你的 Listener 的生命周期! 如果拥有 Listener 的对象被销毁,Listener 将自动为你注销!
如果你需要你的 Event Callback 在 Listener 的线程上执行,从 3.1.0 版本开始... 你可以!
listenerHandle = TemperatureRatingEvent.addListener(self, onTemperatureRatingEvent, executeOn: .listenerThread)
记住: 当在 .listenerThread
上执行 Event Callback 时,你需要确保你的 Callback 及其使用的所有资源都是 100% 线程安全的! 重要: 在 .listnerThread
上执行 Event Callback 可能会延迟其他 Event Callbacks 的调用。 仅在必要时使用此选项。
你也可以在 ad-hoc Task
上执行你的 Event Callback
listenerHandle = TemperatureRatingEvent.addListener(self, onTemperatureRatingEvent, executeOn: .taskThread)
记住: 当在 .taskThread
上执行 Event Callback 时,你需要确保你的 Callback 及其使用的所有资源都是 100% 线程安全的!
关于上面示例的另一点是 listenerHandle
。 每当你注册一个 Listener 时,它将返回一个 EventListenerHandling
对象。 你可以使用此值随时取消注册你的 Listener
listenerHandle.remove()
这将删除你的 Listener Callback,这意味着当 TemperatureRatingEvent
被 Dispatched 时,它将不再被调用。
注意: 这是 4.1.0 版本的改进,而不是使用以前版本中未类型化的 UUID
。
EventListener
是 EventDrivenSwift
的一个极其通用且非常强大的补充。
该库的 4.3.0 版本引入了仅最新侦听器的概念。 仅最新侦听器是一个 Listener,它仅针对其请求的 Event Type 的最新 Event 被调用。 如果在此类型的队列/堆栈中存在许多较旧的 Events 等待处理,它们将被简单地跳过... 并且只有最新的 Event 才会调用你的 Listener。
我们使你能够非常简单地将你的 Listener 配置为 仅最新侦听器。 采用前面的代码示例,我们可以简单地对其进行如下修改
class TemperatureRatingViewModel: ObservableObject {
@Published var temperatureInCelsius: Float
@Published var temperatureRating: TemperatureRating
var listenerHandle: EventListenerHandling?
internal func onTemperatureRatingEvent(_ event: TemperatureRatingEvent, _ priority: EventPriority, _ dispatchTime: DispatchTime) {
temperatureInCelsius = event.temperatureInCelsius
temperatureRating = event.temperatureRating
}
init() {
// Let's register our Event Listener Callback!
listenerHandle = TemperatureRatingEvent.addListener(self, onTemperatureRatingEvent, interestedIn: .latestOnly)
}
}
通过在针对任何 Eventable
类型调用 addListener
时包含 interestedIn
可选参数,并为此参数传递 .latestOnly
值,我们定义此 Listener 仅对要 Dispatched 的最新 TemperatureRatingEvent
感兴趣。 如果在队列/堆栈中累积了许多 TemperatureRatingEvent
s,则上述定义的 Listener 将简单地丢弃任何较旧的 Events,而仅针对最新的 Event 调用。
该库的 5.1.0 版本引入了最大年龄侦听器的概念。 最大年龄侦听器是一个 Listener,它仅针对比定义的最大年龄更年轻的其注册的 Event Type 的 Events 被调用。 任何比定义的最大年龄大的 Event 都将被跳过,而任何年轻的 Event 都将调用你的 Listener。
我们使你能够简单地配置你的 Listener 以定义最大年龄兴趣。 采用前面的代码示例,我们可以简单地对其进行如下修改
class TemperatureRatingViewModel: ObservableObject {
@Published var temperatureInCelsius: Float
@Published var temperatureRating: TemperatureRating
var listenerHandle: EventListenerHandling?
internal func onTemperatureRatingEvent(_ event: TemperatureRatingEvent, _ priority: EventPriority, _ dispatchTime: DispatchTime) {
temperatureInCelsius = event.temperatureInCelsius
temperatureRating = event.temperatureRating
}
init() {
// Let's register our Event Listener Callback!
listenerHandle = TemperatureRatingEvent.addListener(self, onTemperatureRatingEvent, interestedIn: .youngerThan, maximumAge: 1 * 1_000_000_000)
}
}
在上面的代码示例中,maximumAge
是以纳秒为单位定义的值。 考虑到这一点,1 * 1_000_000_000
将是 1 秒。 这意味着,任何比 1 秒更旧的 TemperatureRatingEvent
都将被 Listener 忽略,而任何比 1 秒更年轻的 TemperatureRatingEvent
都将调用 onTemperatureRatingEvent
方法。
当 Event 用法的上下文具有已知的、固定的到期时间时,此功能非常有用。
该库的 5.2.0 版本引入了 Listeners 的自定义事件过滤概念。
现在,在为 Eventable
类型注册 Listener 时,你可以指定一个 customFilter
Callback,该 Callback 最终返回一个 Bool
,其中 true
表示 Listener 对 Event 感兴趣,而 false
表示 Listener 对 Event 不感兴趣。
我们使你能够简单地为你的 Listener 配置一个自定义过滤器。 采用前面的代码示例,我们可以简单地对其进行如下修改
class TemperatureRatingViewModel: ObservableObject {
@Published var temperatureInCelsius: Float
@Published var temperatureRating: TemperatureRating
var listenerHandle: EventListenerHandling?
internal func onTemperatureRatingEvent(_ event: TemperatureRatingEvent, _ priority: EventPriority, _ dispatchTime: DispatchTime) {
temperatureInCelsius = event.temperatureInCelsius
temperatureRating = event.temperatureRating
}
internal func onTemperatureRatingEventFilter(_ event: TemperatureRatingEvent, _ priority: EventPriority, _ dispatchTime: DispatchTime) -> Bool {
if event.temperatureInCelsius > 50 { return false } // If the Temperature is above 50 Degrees, this Listener is not interested in it!
return true // If the Temperature is NOT above 50 Degrees, the Listener IS interested in it!
}
init() {
// Let's register our Event Listener Callback!
listenerHandle = TemperatureRatingEvent.addListener(self, onTemperatureRatingEvent, interestedIn: .custom, customFilter: onTemperatureRatingEventFilter)
}
}
上面的代码将确保仅针对 temperatureInCelsius
小于或等于 50 摄氏度的 TemperatureRatingEvent
调用 onTemperatureRatingEvent
方法。 任何 temperatureInCelsius
大于 50 的 TemperatureRatingEvent
都将被此 Listener 忽略。
4.0.0 版本引入了极其强大的 EventPool
解决方案,使得可以创建 EventThread
的托管组,其中入站 Events 将在任何给定时刻被定向到 EventPool
中最好的 EventThread
。
EventDrivenSwift
使得为任何给定的 EventThread
类型生成 EventPool
变得非常简单。
要从之前的 TemperatureProcessor
示例创建一个 EventPool
,我们可以使用一行代码
var temperatureProcessorPool = EventPool<TemperatureProcessor>(capacity: 5)
上面的示例将创建一个 TemperatureProcessor
的 EventPool
,其初始容量为 5 个实例。 这意味着你的程序可以并发地处理 5 个 TemperatureEvent
s。 显然,对于像我们之前的示例一样简单且快速完成的过程,不需要生成 EventPool
,但你可以将此示例用于你自己的、更复杂且耗时的 EventThread
实现,以立即并行化它们。
EventPool
允许您在初始化时指定最适合上下文的 Balancer (平衡器)。
var temperatureProcessorPool = EventPool<TemperatureProcessor>(capacity: 5, balancer: EventPoolRoundRobinBalancer())
上面的例子将使用 EventPoolRoundRobinBalancer
实现,它只是将每个入站的 Eventable
指向池中的下一个 EventThread
,在使用池中的最后一个 EventThread
后,会循环回到第一个 EventThread
。
在 4.0.0 版本中还有另一个 Balancer (平衡器)可用
var temperatureProcessorPool = EventPool<TemperatureProcessor>(capacity: 5, balancer: EventPoolLowestLoadBalancer())
上面的例子将使用 EventPoolLowestLoadBalancer
实现,它只是将每个入站的 Eventable
指向池中 Queue (队列)和 Stack (堆栈)中待处理的 Eventable
数量最少的 EventThread
。
注意: 如果没有声明 balancer
,EventPool
默认会使用 EventPoolRoundRobinBalancer
。
EventDrivenSwift
是一个不断发展和改进的库,以下是您可以在未来版本中期待的功能列表。
5.1.0 版本 (如果需要破坏接口的更改,则为 6.0.0 版本)
EventPool
实例的动态缩放将完全实现 (目前,不会发生自动缩放,并且一旦初始化 Event Pool,您就无法更改其规模)EventDrivenSwift
在 MIT 许可证下可用。 有关更多信息,请参见 LICENSE 文件。
如果您需要其他支持,或者想讨论 EventDrivenSwift
,Swift 或与 Flowduino 相关的任何其他主题,可以 加入我们的 Discord。