Causality
Causality
是一个简单的线程安全的 Swift 内存总线,它支持完全类型的 Event 和 State。
此外,Causality
还提供了监控 State
信息的功能。State
与 Event
类似,但存在以下区别:
State
处理器将立即接收最后一个已知的好值(如果有的话)- 当状态值与上一个值相同时不调用
State
处理器 - 而一个
Event
有一个关联的Message
,一个State
有一个关联的Value
。 - 状态值的
Value
必须符合 Equatable 协议。
安装
Swift 包管理器
将 Causality
包添加到您的应用程序 Package.swift
文件中的依赖项中。用最新的 Causality
发行版 替换 "x.y.z"。
.package(url: "https://github.com/dannys42/Causality.git", from: "x.y.z")
将 Causality
添加到目标依赖中
.target(name: "example", dependencies: ["Causality"]),
CocoaPods
将 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)
带有关联数据的事件
事件可以包括任何类型的数据(称为消息
)。事件标签完全类型指定了消息。因此,订阅者将能够为其处理器提供完全类型化的消息。
定义消息
消息可以是标准的Swift类型,如Int
、String
等。它也可以是一个遵循Causality.Message
的struct
或class
。请注意,对于消息,您想要值语义还是引用语义。一般来说,值语义(即struct
)会更安全。在这个例子中,我们将声明一个struct
struct InterestingMessage: Causality.Message {
let string: String
let number: Int
}
声明事件
事件可以被声明为具有相关的消息
。如果已声明,消息
是发布事件时必需的类型参数。并且同样地,它将被作为类型参数提供给事件的订阅者。
声明带有消息的事件
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))
状态
定义状态值
类似于一个 事件
,一个 状态
带有一个关联的 值
。值可以是原始类型,如 Int
,String
等。或者它们可以是 struct
或 class
。 (类似于一个事件 消息
,您通常会想使用一个 struct
。)然而,一个 值
必须遵守 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()
函数以指定“键”参数。这些参数用于唯一标识状态。例如
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 文档
更多信息请访问我们的 API 参考。
相关项目
许可证
该库遵循Apache 2.0许可。完整的许可证文本可以在LICENSE中获取。