如何编写有条件发布的发布者?
How to write publisher that conditionally publish?
假设我有这样的发布商:
NotificationCenter.default.publisher(for: NSNotification.Name.NSManagedObjectContextObjectsDidChange)
.map { notification in /.. do something ../}
如何才能在我的区块中阻止发布者发布?
我可以将其设为 trymap,然后抛出错误。但是不得不抛出只是为了表明缺少结果真是太奇怪了(在这种情况下,假设是一个不相关的 NSManagedObject 更改)
这是基于可连接发布者的可能方法(该演示基于 SwiftUI)。使用 Xcode 11.3.1 / iOS 13.3
测试
struct TestConnectableNotification: View {
let publisher = NotificationCenter.default.publisher(for: Notification.Name("test")).makeConnectable()
@State private var text = "<none>"
@State private var subscriber: Cancellable? = nil
var body: some View {
VStack {
Text("Current: \(text)")
.onReceive(publisher) { _ in
let value = Int.random(in: 0..<10)
self.text = "\(value)"
}
Button(self.subscriber == nil ? "Enable" : "Disable") {
if nil == self.subscriber {
self.subscriber = self.publisher.connect()
} else {
self.subscriber?.cancel()
self.subscriber = nil
}
}
Button("Post") {
NotificationCenter.default.post(name: NSNotification.Name("test"), object: nil)
}
}
}
}
另一种方法是使用 flatMap
并发出 Empty 作为拦截器(否则为 Just):
NotificationCenter.default.publisher(for: .NSManagedObjectContextObjectsDidChange)
.flatMap { input -> AnyPublisher<Notification, Never> in
if somethingOrOther {
return Just(input).eraseToAnyPublisher()
} else {
return Empty().eraseToAnyPublisher()
}
}
一种方法是使用 filter
运算符。如果谓词为真,这会将原始输入传递到下游:
NotificationCenter.default.publisher(for: .NSManagedObjectContextObjectsDidChange)
.filter { note in note.object === myContext }
.map { note in /.. do something ../}
另一种方法(bscothern 在评论中提到)是使用 compactMap
。您可以将输入转换为不同的输出,或者如果想抑制输出则转换为 nil:
NotificationCenter.default.publisher(for: .NSManagedObjectContextObjectsDidChange)
.compactMap { note in note.object === myContext ? myContext : nil }
.map { context in /.. do something ../}
假设我有这样的发布商:
NotificationCenter.default.publisher(for: NSNotification.Name.NSManagedObjectContextObjectsDidChange)
.map { notification in /.. do something ../}
如何才能在我的区块中阻止发布者发布?
我可以将其设为 trymap,然后抛出错误。但是不得不抛出只是为了表明缺少结果真是太奇怪了(在这种情况下,假设是一个不相关的 NSManagedObject 更改)
这是基于可连接发布者的可能方法(该演示基于 SwiftUI)。使用 Xcode 11.3.1 / iOS 13.3
测试struct TestConnectableNotification: View {
let publisher = NotificationCenter.default.publisher(for: Notification.Name("test")).makeConnectable()
@State private var text = "<none>"
@State private var subscriber: Cancellable? = nil
var body: some View {
VStack {
Text("Current: \(text)")
.onReceive(publisher) { _ in
let value = Int.random(in: 0..<10)
self.text = "\(value)"
}
Button(self.subscriber == nil ? "Enable" : "Disable") {
if nil == self.subscriber {
self.subscriber = self.publisher.connect()
} else {
self.subscriber?.cancel()
self.subscriber = nil
}
}
Button("Post") {
NotificationCenter.default.post(name: NSNotification.Name("test"), object: nil)
}
}
}
}
另一种方法是使用 flatMap
并发出 Empty 作为拦截器(否则为 Just):
NotificationCenter.default.publisher(for: .NSManagedObjectContextObjectsDidChange)
.flatMap { input -> AnyPublisher<Notification, Never> in
if somethingOrOther {
return Just(input).eraseToAnyPublisher()
} else {
return Empty().eraseToAnyPublisher()
}
}
一种方法是使用 filter
运算符。如果谓词为真,这会将原始输入传递到下游:
NotificationCenter.default.publisher(for: .NSManagedObjectContextObjectsDidChange)
.filter { note in note.object === myContext }
.map { note in /.. do something ../}
另一种方法(bscothern 在评论中提到)是使用 compactMap
。您可以将输入转换为不同的输出,或者如果想抑制输出则转换为 nil:
NotificationCenter.default.publisher(for: .NSManagedObjectContextObjectsDidChange)
.compactMap { note in note.object === myContext ? myContext : nil }
.map { context in /.. do something ../}