EventBus
EventBus 是 Cocoa 的 NSNotificationCenter
的一个安全默认替代方案。它提供了一个 类型安全的 API,可以安全地在多个线程中使用。它会在订阅者被释放时自动移除订阅。
EventBus 对 一对多通知 的作用就像 Delegate
对一对一通知的作用。
用法
简单通知
假设您有一个抽奖活动,每当抽出一个新的中奖号码时,应该通知所有参与的玩家
import EventBus
protocol LotteryDraw {
func didDraw(number: Int, in: Lottery)
}
class Lottery {
private let eventBus = EventBus()
func add(player: LottoPlayer) {
self.eventBus.add(subscriber: player, for: LotteryDraw.self)
}
func draw() {
let winningNumber = arc4random()
self.eventBus.notify(LotteryDraw.self) { subscriber in
subscriber.didDraw(number: Int(winningNumber), in: self)
}
}
}
class LottoPlayer : LotteryDraw {
func didDraw(number: Int, in: Lottery) {
if number == 123456 { print("Hooray!") }
}
}
复杂通知
很好,但如果您想要将一组 语义相关的通知(例如过程的各个阶段)组合成一个通用协议怎么办?没问题!您的协议可以是任何 复杂度。
考虑以下简单的键值观察场景:
import EventBus
protocol ValueChangeObserver {
func willChangeValue(of: Publisher, from: Int, to: Int)
func didChangeValue(of: Publisher, from: Int, to: Int)
}
class Publisher {
private let eventBus = EventBus()
var value: Int {
willSet {
self.eventBus.notify(ValueChangeObserver.self) { subscriber in
subscriber.willChange(value: self.value, to: newValue)
}
}
didSet {
self.eventBus.notify(ValueChangeObserver.self) { subscriber in
subscriber.didChange(value: oldValue, to: self.value)
}
}
}
func add(subscriber: ValueChangeObserver) {
self.eventBus.add(subscriber: subscriber, for: ValueChangeObserver.self)
}
}
class Subscriber : ValueChangeObserver {
func willChangeValue(of: Publisher, from: Int, to: Int) {
print("\(of) will change value from \(from) to \(to).")
}
func didChangeValue(of: Publisher, from: Int, to: Int) {
print("\(of) did change value from \(from) to \(to).")
}
}
链式处理
有时可能希望一个事件总线将所有事件的原件转发到另一个事件总线。一个可能的场景是代理事件总线,它作为一个中心门面来访问任意数量内部事件总线。
let proxyEventBus = EventBus()
let eventBus1 = EventBus()
let eventBus2 = EventBus()
proxyEventBus.attach(chain: eventBus1, for SomeEvent.self)
proxyEventBus.attach(chain: eventBus2, for SomeEvent.self)
let subscriber1 = …
let subscriber2 = …
eventBus1.add(subscriber: subscriber1, for: SomeEvent.self)
eventBus2.add(subscriber: subscriber2, for: SomeEvent.self)
proxyEventBus.notify(SomeEvent.self) { subscriber in
// …
}
// subscriber1 & subscriber2 are getting notified
对eventBus1
或eventBus2
上通知的每个事件,都将在proxyEventBus
上转发一个原件。
封装
EventBus的API分为以下协议:
EventRegistrable
EventSubscribable
EventChainable
EventNotifiable
这使封装更加实现对 [...] 安全高效的封装...
public class Publisher {
public var eventSubscribable: EventSubscribable {
return self.eventBus
}
private let eventBus: EventBus = …
// …
}
... 防止其他人发出对 Publisher
事件总线上的通知。
调试
由于无法从EventBus
的类型得知期望接收的事件种类或允许在它上发出的通知,EventBus提供了可选措施,以提前捕捉不当使用并通过一般调试提供帮助。
调试未注册事件类型的订阅
let eventBus = EventBus(options: [.warnUnknown])
eventBus.register(forEvent: FooEvent.self)
// Needed to silence warning:
// eventBus.register(forEvent: BarEvent.self)
let subscriber = …
eventBus.add(subscriber: subscriber, for: BarEvent.self)
// Console:
// Expected event of registered type (e.g. FooEvent), found: BarEvent.
// Info: Use a "Swift Error Breakpoint" on type "EventBus.UnknownEventError" to catch.
调试未注册事件类型的发出通知
let eventBus = EventBus(options: [.warnUnknown])
eventBus.register(forEvent: FooEvent.self)
// Needed to silence warning:
// eventBus.register(forEvent: BarEvent.self)
eventBus.notify(FooEvent.self) { subscriber in
// …
}
// Console:
// Expected event of registered type (e.g. FooEvent), found: BarEvent.
// Info: Use a "Swift Error Breakpoint" on type "EventBus.UnknownEventError" to catch.
调试未处理的事件
let eventBus = EventBus(options: [.warnUnhandled])
// Needed to silence warning:
// eventBus.add(subscriber: …, for: FooEvent.self)
eventBus.notify(FooEvent.self) { subscriber in
// …
}
// Console:
// Expected event of registered type (e.g. FooEvent), found: BarEvent.
// Info: Use a "Swift Error Breakpoint" on type "EventBus.UnhandledEventError" to catch.
安装
将 EventBus 添加到项目中的推荐方法是通过 Carthage
github 'regexident/EventBus'
或者可以通过 CocoaPods 将 EventBus 添加到项目中
pod 'Swift-EventBus'
许可证
EventBus 使用 修改后的 BSD-3 条款许可证 提供。更多信息请参阅 LICENSE
文件。