PonyExpress
提供了一种类型安全的替代方案来代替 NotificationCenter
。
查看 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))
有多种方法可以接收通知。所有观察者都定义了他们想要接收的通知类型,只有与这些类型匹配的通知才会被接收。如果指定了发送者,则该发送者的类型也必须匹配。
就像在 NotificationCenter
中一样,该对象被弱引用持有,并且在对象 dealloc 时不需要显式地取消注册。
class MyClass {
func init() {
PostOffice.default.register(self, MyClass.receive)
}
func receive(notification: ExampleNotification, sender: ExampleSender) {
// process the notification
}
}
可以将代码块或方法传递到 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)
在 PostOffice
注册时,接收者可以选择在哪个 DispatchQueue
上收到通知。如果未指定队列,则通知将在发布通知的队列上同步发送。如果指定了队列,则通知将在该队列上异步发送。
PostOffice.default.register(queue: myDispatchQueue, recipient, MyClass.receive)
使用 NotificationCenter
的通知通过通知的 [String: Any]
userInfo
属性发送。这意味着该通知的任何观察者都需要使用类似 guard let myStuff = notification.userInfo["someProperty"] as? MyStuff
的代码来解码 userInfo。
这存在一些问题
"someProperty"
可能包含拼写错误。使用常量容易出现复制/粘贴错误。userInfo
键和实际值Float
并尝试解码 CGFloat
将会静默失败(或运行时错误)。在 PonyExpress
中,目标是减少冗余并将错误从运行时转移到编译时。
String
名称或键 - 只有实际数据在没有任何额外样板的情况下发送喜欢 PonyExpress
吗? 表达感谢 并请我喝杯咖啡 ☕️!