首页 > 解决方案 > Swift Combine:合并多个发布者并在其中任何一个发出“真”时发出“真”

问题描述

我正在尝试建立一个发布者,当其他 5 个发布者中的任何一个发布为 true 时,该发布者会发出 true。我已经设法构建了一个工作版本,但使用 CombineLatest4 + CombineLatest 尤其是所有$0.0 || $0.1 || $0.2 || $0.3代码感觉非常恶心。

我已经尝试过 Merge5,但这只是返回似乎设置的最后一个值的值。

import Foundation
import Combine

class Test {
  @Published var one = false
  @Published var two = false
  @Published var three = false
  @Published var four = false
  @Published var five = false
}

let test = Test()

var anyTrue = Publishers.CombineLatest4(test.$one, test.$two, test.$three, test.$four)
  .map { $0.0 || $0.1 || $0.2 || $0.3 }
  .combineLatest(test.$five)
  .map { $0.0 || $0.1 }

anyTrue.sink {
  print($0)
}

test.three = true
test.one = false

有没有更清洁、重复性更低的方法来做到这一点?

标签: swiftcombine

解决方案


我编写了这个combineLatest结合了 N 个发布者的自定义可变参数函数。希望这是您需要的:

func combineLatestN<P, T, E>(identity: T, reductionFunction: @escaping (T, T) -> T, publishers: P...) -> AnyPublisher<T, E> 
    where P: Publisher, P.Output == T, P.Failure == E {
    publishers.reduce(
        Publishers.Sequence<[T], E>(sequence: [identity]).eraseToAnyPublisher(), 
        { $0.combineLatest($1).map(reductionFunction).eraseToAnyPublisher() }
    )
}

困难的部分是弄清楚reduce应该是什么身份。什么出版商x能满足x.combineLatest(y).map(f) == y所有人y?一种解决方案x是发布f一次身份的发布者。

用法:

let anyTrue = combineLatestN(
                identity: false, 
                reductionFunction: { $0 || $1 }, 
                publishers: test.$one, test.$two, test.$three, test.$four, test.$five)

推荐阅读