PonyExpress

PonyExpress 提供了一种类型安全的替代方案来代替 NotificationCenter

CI

文档

查看 PonyExpress 的文档。可以使用包含的 builddocs.sh 脚本构建 Xcode 文档。

$ ./builddocs.sh

还需要 jq 工具来格式化生成的 docc json 文件。

$ brew install jq

安装

PonyExpress 可作为 Swift 包使用。

.package(url: "https://github.com/adamwulf/PonyExpress.git", .branch("main"))

https://github.com/adamwulf/PonyExpress.git

快速开始

任何对象或值都可以作为通知发送。接收者注册一个处理方法来接收对象类型。

示例

struct ExampleNotification: Mail {
    var info: Int
    var other: Float
}

class ExampleRecipient {
    init() {
        PostOffice.default.register(self, ExampleRecipient.receive)
    }

    func receive(notification: ExampleNotification) {
        // ... process the notification
    }
}

// Send the notification ...
let recipient = ExampleRecipient()
PostOffice.default.post(ExampleNotification(info: 12, other: 15))

发送通知

任何实现空 Mail 协议的对象都可以作为通知发送,只有注册了该通知类型的接收者才会收到它。

// Send a struct with the above example, or send an enum, or any other type.
enum ExampleEnum: Mail {
    case fumble
    case mumble(bumble: Int)
}

PostOffice.default.register { (mail: ExampleEnum) in
    // ... process the notification
}

PostOffice.default.post(ExampleEnum.mumble(bumble: 12))

观察通知

有多种方法可以接收通知。所有观察者都定义了他们想要接收的通知类型,只有与这些类型匹配的通知才会被接收。如果指定了发送者,则该发送者的类型也必须匹配。

选项 1:注册对象和方法

就像在 NotificationCenter 中一样,该对象被弱引用持有,并且在对象 dealloc 时不需要显式地取消注册。

class MyClass {
    func init() {
        PostOffice.default.register(self, MyClass.receive) 
    }
    
    func receive(notification: ExampleNotification, sender: ExampleSender) {
        // process the notification
    }
}

选项 2:注册一个代码块

可以将代码块或方法传递到 PostOffice 以观察通知。代码块在 PostOffice 中被强引用持有,必须显式地取消注册。

class MyClass {
    var token: RecipientId? 
    
    func init() {
        PostOffice.default.register { [weak self] (notification: ExampleNotification) in
            // process the notification
        }
    }
}

取消注册

每个 register() 方法都会返回一个 RecipientId,该 ID 可用于取消注册接收者。

let recipient = ExampleRecipient()
let id = PostOffice.default.register(recipient)
...
PostOffice.default.unregister(id)

发送者

发送通知可以选择性地包含一个 sender。这与 NotificationCenter 类似,接收者可以选择性地注册仅从特定发送者发送的通知。在 PonyExpress 中,通知和发送者都是强类型的。

接收者可以选择在接收代码块或方法中包含或排除发送者参数。

class ExampleRecipient {
    init() {
        PostOffice.default.register(self, ExampleRecipient.receiveWithOptionalSender)
        PostOffice.default.register(self, ExampleRecipient.receiveWithSender)
        PostOffice.default.register(self, ExampleRecipient.receiveWithoutSender)
    }

    // An optional sender will require that the sender of the notification either
    // a) match the type of the `sender`, or b) be `nil`
    func receiveWithOptionalSender(notification: ExampleNotification, sender: ExampleSender?) {
        // ... process the notification
    }

    // An non-optional sender will require that the sender of the notification either match
    // the `sender` type
    func receiveWithSender(notification: ExampleNotification, sender: ExampleSender) {
        // ... process the notification
    }

    // Omitting a `sender` parameter will receive notifications for senders of any type, even nil senders
    func receiveWithoutSender(notification: ExampleNotification) {
        // ... process the notification
    }
}

// recipients can also register to receive notifications from a singular exact-match sender
let sender = ExampleSender()
let recipient = ExampleRecipient()
PostOffice.default.register(sender: sender, recipient, ExampleRecipient.receiveWithSender) 
PostOffice.default.register(sender: sender, recipient, ExampleRecipient.receiveWithoutSender) 

在发布通知时,可以选择性地提供发送者。

PostOffice.default.post(ExampleNotification(info: 12, other: 15), sender: sender)

DispatchQueues

PostOffice 注册时,接收者可以选择在哪个 DispatchQueue 上收到通知。如果未指定队列,则通知将在发布通知的队列上同步发送。如果指定了队列,则通知将在该队列上异步发送。

PostOffice.default.register(queue: myDispatchQueue, recipient, MyClass.receive) 

动机

使用 NotificationCenter 的通知通过通知的 [String: Any] userInfo 属性发送。这意味着该通知的任何观察者都需要使用类似 guard let myStuff = notification.userInfo["someProperty"] as? MyStuff 的代码来解码 userInfo。

这存在一些问题

PonyExpress 中,目标是减少冗余并将错误从运行时转移到编译时。

谢谢!❤️

喜欢 PonyExpress 吗? 表达感谢 并请我喝杯咖啡 ☕️!