如何将信号数组合并为单个信号 ReactiveCocoa 4

How to merge Array of Signals into a single Signal ReactiveCocoa 4

在我的设置中,我有一个由许多 GridViewCell 组成的 GridView。每个单元格都有一个 UITapGestureRecognizer

为了方便起见,GridView有如下函数 func cellsTapGestureRecognizers() -> [UITapGestureRecognizer?] returns 其所有单元格的 UITapGestureRecognizers(如果它们存在)。

在使用 GridViewUIViewController 中,我的目标是将点击视为 Signal。我设法做到了这一点,但有一个限制,即我为每个 GridViewCell 创建了一个 Signal,这似乎是不必要的。

func createTapSignals() -> [Signal<Position, NoError>?] {
    var signals: [Signal<Position, NoError>] = []
    for maybeTap in self.gridView.cellsTapGestureRecognizers() {
        if let tap = maybeTap {
            let signal = tap.gestureSignalView()
                .map { [=10=] as! GridViewCell }
                .map {[=10=].position}
            signals.append(signal)
        }
    }
    return signals
}

是否可以合并在 createTapSignals() 中创建的所有信号,以便最后只剩下一个 Signal<Position, NoError> 类型的信号?

我查看了 documentation,但只找到了如何使用 flatten(.Merge) 合并 SignalProducers 的方法。是否有类似的方法可以合并 SignalArray

注意上面函数中使用的 gestureSignalView() returns 一个 Signal<UIView, NoError> 携带 UITapGestureRecognizerUIView (灵感来自@NachoSoto's gist).

我在 RAC Github repo 中搜索后自己找到了解决方案。

(静态)函数 merge 正是我要找的。它是 SignalType 协议(Signal 符合)的一部分,并在协议扩展中实现。

所以,我只能执行以下操作:

let signals = createTapSignals()
let mergedSignal = Signal.merge(signals)

作为参考,下面是 merge 的实现方式:

public static func merge<S: SequenceType where S.Generator.Element == Signal<Value, Error>>(signals: S) -> Signal<Value, Error> {
    let producer = SignalProducer<Signal<Value, Error>, Error>(values: signals)
    var result: Signal<Value, Error>!

    producer.startWithSignal { (signal, _) in
        result = signal.flatten(.Merge)
    }

    return result
}