ylliX - Online Advertising Network

RxSwift: How to stream values with dynamic delay

Imagine such case – you have list of messages, each one with timestamp. And you want to show them in the same way they arrived, with same timings. How to achieve this with RxSwift?

Lets start with test structure, which in our example will hold only basic data, but feel free to modify it as you want:

struct testStruct {
    var delay = 0.0
    var number = 0
}

Note “delay” attribute, which holds value after each message should be shown. Then you can create array of messages:

let items = [
    testStruct(delay: 0.3, number: 1),
    testStruct(delay: 1.2, number: 2),
    testStruct(delay: 0.2, number: 3),
    testStruct(delay: 0.5, number: 4),
    testStruct(delay: 0.8, number: 5),
]

Of course in real world, this array will be fetched from database or JSON. Then next step is stream each one this way:

let sb = PublishSubject()
var delay = 0.0
sb
    .flatMap { n -> Observable in
        delay = delay + n.delay
        return Observable.just(n).delaySubscription(RxTimeInterval(delay), scheduler: MainScheduler.instance)
    }
    .subscribe(onNext: { (i) in
        NSLog("i \(i)")
    })
    .addDisposableTo(disposeBag)
        
    items.forEach({ (inp) in
        sb.onNext(inp)
    })

What happens here? First we are declaring our “delay” variable, which will cumulate delay for each next message. Note that this is not perfect, as with big arrays, parsing flatMap can take some time, and messages can be delayed because of this. But usually it is enough. Next comes the most important step – for each incoming element, we are returning Observable type for element itself, but with delayed subscription. This will cause .subscribe() to be executed after given delay.

The final step is to push each element from array, to our PublishSubject. In given case, your output should look like this:

2017-04-26 18:33:34.410 i testStruct(delay: 0.29999999999999999, number: 1)
2017-04-26 18:33:35.610 i testStruct(delay: 1.2, number: 2)
2017-04-26 18:33:35.811 i testStruct(delay: 0.20000000000000001, number: 3)
2017-04-26 18:33:36.311 i testStruct(delay: 0.5, number: 4)
2017-04-26 18:33:37.112 i testStruct(delay: 0.80000000000000004, number: 5)

As you can see, we started output at 18:33:34.110, then next element is delayed by 0.3 sec, and displayed at 18:33:34.410, next is delayed by 1.2 sec and displayed at 18:33:35.610, and so on. Each one, exactly in same order we put them into subject. And don’t forget to add :

let disposeBag = DisposeBag()

as your view controller property.

Leave a Reply