RxSwiftにおいて、要素がストリームに同期的にemitされる時と非同期にemitされる時とで、コードの実行順序がどうなるかを調べました。
また、スケジューラを使ってスレッドを切り替えるとどうなるかも調べました。
知りたいこと
以下のコードで、someObservable
が要素を同期的にemitする時と、非同期にemitする時で、どちらのprint
文が先に実行されるかが知りたい。
someObservable
.subscribe(onNext: { element in
print("world")
})
.disposed(by: disposeBag)
print("hello")
やってみた
Observableを返すメソッドを持つ以下のようなクラスを作る。
class API {
// 要素が同期的にemitされる
func sync() -> Observable<String> {
return Observable.create { observer in
observer.onNext("sync")
observer.onCompleted()
return Disposables.create()
}
}
// 要素が非同期にemitされる
func async() -> Observable<String> {
return Observable.create { observer in
DispatchQueue.main.async {
observer.onNext("async")
observer.onCompleted()
}
return Disposables.create()
}
}
}
同期的にemitされるケース
let api = API()
api.sync()
.subscribe(onNext: { str in
print("@@@ subscribe: \(str) @@@")
})
.disposed(by: disposeBag)
print("### sync test ###")
実行結果は以下の通り。
subscribe内のクロージャが先に実行されている。
@@@ subscribe: sync @@@
### sync test ###
非同期にemitされるケース
let api = API()
api.async()
.subscribe(onNext: { str in
print("@@@ subscribe: \(str) @@@")
})
.disposed(by: disposeBag)
print("### async test ###")
実行結果は以下の通り。
こちらはsubscribe内のクロージャが後に実行された。
### async test ###
@@@ subscribe: async @@@
同期的にemitされるストリームにバックグラウンドスレッドでサブスクライブさせる
スケジューラを使って、subscribeがバックグラウンドスレッドで実行されるようにしてみる。
let api = API()
api.sync()
.observeOn(SerialDispatchQueueScheduler(qos: .background)) // 追加!
.subscribe(onNext: { str in
print("@@@ subscribe: \(str) @@@")
})
.disposed(by: disposeBag)
print("### sync test ###")
実行結果は以下の通り。
subscribe内のクロージャが後に実行された。
### sync test ###
@@@ subscribe: sync @@@