Causality
是一个简单的线程安全、内存中的 Swift 总线,支持完全类型化的事件 (Events) 和状态 (States)。
此外,Causality
提供了监控 State
信息的功能。State
类似于 Event
,但不同之处在于:
State
处理程序将立即使用最后一次已知的有效值(如果可用)进行调用。State
处理程序。Event
具有关联的 Message
,而 State
具有关联的 Value
。Value
必须符合 Equatable 协议。将 Causality
包添加到应用程序的 Package.swift
文件中的依赖项。 将 "x.y.z" 替换为最新的 Causality
版本。
.package(url: "https://github.com/dannys42/Causality.git", from: "x.y.z")
将 Causality
添加到您的目标的依赖项中。
.target(name: "example", dependencies: ["Causality"]),
将 Causality
添加到您的 Podfile。
pod `Causality`
最简单的事件管理方式是不包含任何关联数据。
这将声明一个名为 aTriggerEvent
的事件,该事件没有关联的数据。
struct MyEvents {
static let aTriggerEvent = Causality.Event<Causality.NoMessage>(label: "A Trigger")
}
要订阅此事件
let subscription = Causality.bus.subscribe(MyEvents.aTriggerEvent) { _ in
print("Event was triggered")
}
要发布/发送此类型的事件
Causality.bus.publish(MyEvents.aTriggerEvent)
事件可以包含任何类型的数据(称为 Message
)。 事件标签是完全类型指定的,带有消息。 因此,订阅者将有一个完全类型化的消息可供其处理程序使用。
消息可以是标准的 Swift 类型,如 Int
、String
等。或者它可以是符合 Causality.Message
的 struct
或 class
。 请注意您是否需要消息的值或引用语义。 通常,值语义(即 struct
)会更安全。 在此示例中,我们将声明一个 struct
struct InterestingMessage: Causality.Message {
let string: String
let number: Int
}
可以使用关联的 Message
声明事件。 如果声明了,则 Message
是发布事件所需的类型化参数。 同样,它将作为类型化参数提供给事件的订阅者。
使用消息声明事件
let MyInterestingEvent = Causality.Event<SomeMessage>(label: "Some Event")
let MyStringEvent = Causality.Event<String>(label: "An event with a String message")
let MyNumberEvent = Causality.Event<Int>(label: "An event with an Int message")
或对您的事件进行分类
struct MyEvents {
static let MyInterestingEvent = Causality.Event<InterestingMessage>(label: "An interesting Event 1")
static let MyStringEvent = Causality.Event<String>(label: "An event with a String message")
static let MyNumberEvent = Causality.Event<Int>(label: "An event with an Int message")
}
保存您的订阅以便稍后取消订阅
let subscription = Causality.bus.subscribe(MyEvents.MyInterestingEvent) { interestingMessage in
print("A message from MyInterestingEvent: \(interestingMessage)")
}
Casaulity.bus.unsubscribe(subscription)
或者从订阅处理程序中取消订阅。 这是一个一次性事件处理程序的示例
Causality.bus.subscribe(MyEvents.MyStringEvent) { subscription, string in
print("A string from MyStringEvent: \(string)")
subscription.unsubscribe()
}
要发布/发送一个事件
Causality.bus.publish(MyEvents.MyInterestingEvent,
message: InterestingMessage(string: "Hello", number: 42))
为您的总线创建别名
let eventBus = Causality.bus
eventBus.publish(MyEvents.MyInterestingEvent,
message: InterestingMessage(string: "Hello", number: 42))
或者创建本地总线来隔离您的事件
let newEventBus = Causality.Bus(label: "My local bus")
newEventBus.publish(MyEvents.interestingEvent,
message: InterestingMessage(string: "Hello", number: 42))
与 Event
类似,State
具有关联的 Value
。 值可以是原始类型,例如 Int
、String
等。或者它们可以是 struct
或 class
。 (与事件的 Message
类似,您通常需要使用 struct
。)但是,Value
必须符合 Equatable
。
struct PlayerInfo: Causality.StateValue {
let numberOfLives: Int
let health: Int
let armor: Int
}
使用关联的值声明一个状态
let playerState = Causality.State<PlayerInfo>(label: "Player State")
或对您的状态进行分类
struct GameStates {
static let playerState1 = Causality.State<PlayerInfo>(label: "Player 1 State")
static let playerState2 = Causality.State<PlayerInfo>(label: "Player 2 State")
}
保存您的订阅以便稍后取消订阅
let subscription = Causality.bus.subscribe(GameStates.playerState1) { state in
print("Player 1 state changed to: \(state)")
}
Casaulity.bus.unsubscribe(subscription)
或者从订阅处理程序中取消订阅。 此示例将仅监视单个状态更改
Causality.bus.subscribe(GameStates.playerState1) { subscription, message in
print("Player 1 state changed to: \(state)")
subscription.unsubscribe()
}
如果先前已设置状态,则订阅处理程序将立即使用最后一次已知的有效值进行调用。 仅当后续 .set()
调用具有不同的值时,才会调用订阅处理程序。
Causality.bus.set(GameStates.playerState1,
value: PlayerInfo(numberOfLives: 3, health: 75, armor: 10))
在上面的游戏示例中,我们每个状态都有一个 Causality.State 变量。 但是,如果我们有 "n" 个玩家怎么办? 在这种情况下,我们可以使用动态状态。 动态状态允许您参数化您的状态。 动态状态是可编码的 (Codable),需要您定义 CodingKeys
并重载 encode()
函数以指定 "key" 参数。 这些参数用于唯一标识状态。 例如
class PlayerState<Value: PlayerInfo>: Causality.DynamicState<Value> {
let playerId: Int
init(playerId: Int) {
self.playerId = playerId
}
enum CodingKeys: CodingKey {
case playerId
}
override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.playerId, forKey: .playerId)
}
}
现在订阅
Causality.bus.subscribe(PlayerState<PlayerInfo>(playerId: 1)) { subscription, playerInfo in
print("Current player info is: \(playerInfo))
}
或添加更多组织
struct GameState {
static func playerState(_ playerId: Int) -> PlayerState<PlayerInfo> {
return PlayerState<PlayerInfo>(playerId: playerId)
}
}
Causality.bus.subscribe(GameState.playerState(1)) { subscription, playerInfo in
print("Current player info is: \(playerInfo)")
}
以及设置/更新状态
Causality.bus.set(state: GameState.playerState(1),
value: PlayerInfo(
numberOfLines: 3,
health: 75,
armor: 100))
同样,您可以将 Int
、String
等基本类型用作 Value
。
let UserNameState = Causality.State<String>(label: "user name state")
Causality.bus.subscribe(UserNameState) { username in
print("Username is now: \(username)")
}
Causality.bus.set(UserNameState, "Mary Jane Doe")
可以通过以类似方式定义事件来参数化事件
class MyEvent<Message: Causality.Message>: Causality.DynamicEvent<Message> {
let eventId: Int
init(eventId: Int) {
self.eventId = eventId
}
enum CodingKeys: CodingKey {
case eventId
}
override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(self.eventId, forKey: .eventId)
}
}
然后创建事件
struct MyEvents {
static func event(_ eventId: Int) -> MyEvent<InterestingMessage> {
return MyEvent<InterestingMessage>(eventId: eventId)
}
}
订阅事件
let subscription = Causality.bus.subscribe(MyEvents.event(1)) { subscription, message in
print("A message from event \(subscription.event.eventId): \(message)")
}
并发布事件
Causality.bus.publish(MyEvents.event(1),
message: InterestingMessage(string: "Hello", number: 42))
有关更多信息,请访问我们的 API 参考。
此库在 Apache 2.0 许可证下获得许可。 完整的许可证文本可在 LICENSE 中找到。