Search code examples
swiftreactive-programmingreactive-cocoareactive-swift

ReactiveSwift emit elements from an array with a delay between elements


Let's say I have an array of elements [1, 2, 3] and a delay of 5 seconds.

I want to emit each element of the array with a pause between the current element emited and the next.

Example:

Output:

[00:00] -- 1
[00:05] -- 2
[00:10] -- 3

I've tried to do the following:

import ReactiveSwift

let startTime     = DispatchTime.now().uptimeNanoseconds
let arrayProperty = MutableProperty<[Int]>([1, 2, 3])
let arraySignal   = arrayProperty.signal
arraySignal
    .flatMap { $0 }
    .delay(2, on: QueueScheduler.main)
    .observeValues { element in
        let elapsed = DispatchTime.now().uptimeNanoseconds
        print("\((elapsed - startTime) / 1_000_000_000) -- \(element)")
    }

But it only delays the emission of the first element and emits the next ones immediately.

I couldn't find the proper operator mix to use, maybe they are missing on ReactiveSwift framework, and I'm a beginner in Reactive programming so implementing my own operator is way too hard yet.


Solution

  • I haven’t had a chance to try this code, but it should be something like this:

    SignalProducer([1, 2, 3])
        .flatMap(.concat) { n in
            return SignalProducer(value: n).delay(2, on: QueueScheduler.main)
        }
        .startWithValues { element in
            let elapsed = DispatchTime.now().uptimeNanoseconds
            print("\((elapsed - startTime) / 1_000_000_000) -- \(element)")
        }
    

    The key is that you use flatMap to create a new signal producer for each value which you can apply the delay to, and combine them with the .concat flatten strategy.

    (Also, note you can use the signal producer initializer that takes a sequence)