This is a short version of my code which will reproduce the problem:
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
let source = button.rx_tap.map { _ in "source" }
let delay = source.map { _ in "delayed" }
.delaySubscription(2.0, MainScheduler.sharedInstance)
[source, delay].toObservable().merge()
.subscribeNext { print($0) }
.addDisposableTo(disposeBag)
}
}
I want the 'delayed' signal to fire 2 seconds after I tap the button, but no such luck. What actually happens: the first time I tap the button, 'source' fires but nothing else happens. Then when I tap again, 'source' and 'delayed' fire at the same time. I figured it was some thread problem, so I tried adding observeOn(MainScheduler.sharedInstance)
everywhere but it didn't help. Any ideas?
Update: by adding .debug()
to the streams I found out that the delayed stream actually subscribes to the source 2 seconds later. But that still doesn't explain why it doesn't fire its notifications 2 seconds later as well.
To answer my own question, it seems that delaySubscription
only works on cold observables.
A cold observable, like for example a timer
, only starts to fire notifications when it has been subscribed to, and everyone that subscribes to it gets a fresh sequence. This is why simply delaying the subscription on a cold observable will also delay all the notifications.
A hot observable, like a UI event for example, shares the same sequence with all its subscribers, so delaying the subscription has absolutely no influence on its notifications.
Instead, I can use the flatMap
operator to transform each source notification into another observable that fires its only notification after a certain delay, and merges the results of these observables:
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
let source = button.rx_tap.map { _ in "source" }
let delayed = source.flatMap { _ in
timer(1.0, MainScheduler.sharedInstance)
.map { _ in "delayed" }
}
[source, delayed]
.toObservable().merge()
.subscribeNext { print($0) }
.addDisposableTo(disposeBag)
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.