Search code examples
swiftreactive-swiftcombinelatest

Is there a way to make a signal similar to combineLatest without needing all the signals to initially fire?


I have an array of signals

var signals = [Signal<ActionResult?, NoError>]()

where

enum ActionResult
    case failed
    case pending
    case completed
}

I want to create a combined signal that returns true if one or more of the signals fires a .pending

let doesAnyOfTheActionsLoad = Signal.combineLatest(signals).map { values in

     values.reduce(false, { (result, nextResult) -> Bool in
         if result == true { return true }

             if case .pending? = nextResult {
                 return true
             }
         return false
     })
}

My only problem is that the combineLatest will only fire if all signals have fired at least once, and i need my signal to fire regardless if all signals have fired. Is there a way to do this in ReactiveSwift?


Solution

  • The other solutions are technically correct but I thought this might fit your use case better.

    // Only ever produces either a single `true` or a single `false`.
    let doesAnyOfTheActionsLoad = 
        SignalProducer<Bool, NoError>
            .init(signals)
            .flatten(.merge) // Merge the signals together into a single signal.
            .skipNil() // Discard `nil` values.
            .map { $0 == .pending } // Convert every value to a bool representing whether that value is `.pending`.
            .filter { $0 } // Filter out `false`.
            .concat(value: false) // If all signals complete without going to `.pending`, send a `false`.
            .take(first: 1) // Only take one value (so we avoid the concatted value in the case that something loads).