build status macOS iOS Linux Apache 2

因果性 (Causality)

Causality 是一个简单的线程安全、内存中的 Swift 总线,支持完全类型化的事件 (Events) 和状态 (States)。

此外,Causality 提供了监控 State 信息的功能。State 类似于 Event,但不同之处在于:

安装

Swift Package Manager

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"]),

Cocoapods

Causality 添加到您的 Podfile。

pod `Causality`

用法

事件 (Events)

仅是一个事件(没有数据)

最简单的事件管理方式是不包含任何关联数据。

声明事件

这将声明一个名为 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 类型,如 IntString 等。或者它可以是符合 Causality.Messagestructclass。 请注意您是否需要消息的值或引用语义。 通常,值语义(即 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))

事件总线 (Event Buses)

总线别名 (Bus Alias)

为您的总线创建别名

let eventBus = Causality.bus

eventBus.publish(MyEvents.MyInterestingEvent, 
    message: InterestingMessage(string: "Hello", number: 42))

本地总线 (Local Buses)

或者创建本地总线来隔离您的事件

let newEventBus = Causality.Bus(label: "My local bus")

newEventBus.publish(MyEvents.interestingEvent, 
    message: InterestingMessage(string: "Hello", number: 42))

状态 (State)

定义状态值 (State Value)

Event 类似,State 具有关联的 Value。 值可以是原始类型,例如 IntString 等。或者它们可以是 structclass。 (与事件的 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))

动态状态 (Dynamic States)

在上面的游戏示例中,我们每个状态都有一个 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))

同样,您可以将 IntString 等基本类型用作 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")

动态事件 (Dynamic Events)

可以通过以类似方式定义事件来参数化事件

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 中找到。