Swift Combine: объединить несколько издателей и вывести «истину», когда любой из них выдает «истину» - PullRequest
2 голосов
/ 25 мая 2020

Я пытаюсь создать издателя, который излучает истину, когда любой из 5 других издателей излучает истину. Мне удалось создать рабочую версию, но она кажется очень неприглядной, с 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

Есть ли более чистый, менее повторяющийся способ сделать это?

1 Ответ

1 голос
/ 25 мая 2020

Я написал эту настраиваемую вариационную функцию c 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)
...