【问题标题】:How to write publisher that conditionally publish?如何编写有条件发布的发布者?
【发布时间】:2020-03-16 18:25:51
【问题描述】:

假设我有这样的出版商:

NotificationCenter.default.publisher(for: NSNotification.Name.NSManagedObjectContextObjectsDidChange)
  .map { notification in /.. do something ../}

如何在我的区块中阻止发布者发布?

我可以将其设为 trymap,然后引发错误。但是为了表明缺乏结果而不得不抛出是如此奇怪(在这种情况下,假设是一个不相关的 NSManagedObject 更改)

【问题讨论】:

  • 您可以使用compactMap 并在您不想发出值时返回nil

标签: swift combine


【解决方案1】:

一种方法是使用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 ../}

【讨论】:

    【解决方案2】:

    这是基于可连接发布者的可能方法(演示基于 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)
                }
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      另一种方法是使用flatMap 并发出一个 Empty 作为拦截器(否则一个 Just ):

      NotificationCenter.default.publisher(for: .NSManagedObjectContextObjectsDidChange)
          .flatMap { input -> AnyPublisher<Notification, Never> in
              if somethingOrOther {
                  return Just(input).eraseToAnyPublisher()
              } else {
                  return Empty().eraseToAnyPublisher()
              }
          }
      

      【讨论】:

      • 在这种情况下,flapmap 比带有 nils 的 compactmap 有什么优势?
      • 我没说有优势。
      • 我只是好奇这两种方法之间的权衡是什么
      • flatMapcompactMap 更强大。例如,flatMap 可以用任意数量的输出替换单个输入,但compactMap 只能用零个或一个输出替换一个输入。但是,flatMap 也比compactMap 使用起来更复杂,运行时也更昂贵。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多