【RxSwift】subscribe 時に省略系を用いると onNext と onDisposed で同じクロージャが処理されたように見える
環境
- Xcode Version 12.3 (12C33)
- RxSwift 5.0.1
行いたかったこと
- あるイベントをきっかけに一度だけ読み込み処理を行いたい
-
self.subject
にonNext(())
を通す
self.subject
.take(1)
.subscribe(onNext: { [weak self] _ in
// 正常に動作する
guard let self = self else { fatalError() }
self.loadData()
})
.disposed(by: self.disposeBag)
省略すると...
- 以下のように省略して書くと
subscribe
のクロージャが2回呼ばれる
self.subject
.take(1)
.subscribe { [weak self] _ in
// 2回呼ばれてしまう
guard let self = self else { fatalError() }
self.loadData()
}
.disposed(by: self.disposeBag)
検証
実装
以下のような ViewController を作成
-
self.viewDidLoad()
で購読処理を行う - onNext ボタンをタップすると
onNext()
を流す - onCompleted ボタンをタップすると
onCompleted()
を流す - onError ボタンをタップすると
onError(TestError())
を流す
TestViewController.swift
import RxSwift
import UIKit
// MARK: - TestViewController
final class TestViewController: UIViewController {
// MARK: - UIViewController
override func viewDidLoad() {
super.viewDidLoad()
self.subject
.subscribe { (value: Int) in
print("ラベル省略: onNext")
}
.disposed(by: self.disposeBag)
self.subject
.subscribe(onNext: { _ in
print("値省略: onNext")
})
.disposed(by: self.disposeBag)
self.subject
.subscribe { _ in
print("全省略: onNext")
}
.disposed(by: self.disposeBag)
}
// MARK: - Private
private struct TestError: Error {}
@IBAction private func onNextButtonTapped(_ sender: Any) {
print("***** onNext ******")
self.subject.onNext(1)
}
@IBAction private func onCompletedButtonTapped(_ sender: Any) {
print("***** onCompleted ******")
self.subject.onCompleted()
}
@IBAction func onErrorButtonTapped(_ sender: Any) {
print("***** onError ******")
self.subject.onError(TestError())
}
private let subject = PublishSubject<Int>()
private let disposeBag = DisposeBag()
}
試験
A: onNextを1回、onCompletedを1回流す
B: onNextを1回、onErrorを1回流す
結果
A: onCompleted を流した際に全省略のクロージャ内部が処理される
***** onNext ******
ラベル省略: onNext
値省略: onNext
全省略: onNext
***** onCompleted ******
全省略: onNext
B: onError を流した際に全省略のクロージャ内部が処理される
***** onNext ******
ラベル省略: onNext
値省略: onNext
全省略: onNext
***** onError ******
全省略: onNext
原因(2021/4/26 追記)
- 引数を全て省略すると
subscribe(onNext:onError:onCompleted:onDisposed:)
ではなくsubscribe(_ on:)
として解釈されることが原因 -
subscribe(_ on:)
ではonNext
onCompleted
onError
(RxSwift.Event
)それぞれのタイミングで同じクロージャが処理される-
subscribe(onNext:onError:onCompleted:onDisposed:)
のonNext
とonDisposed
で同じクロージャが処理されているように見えていた
-
結論
- RxSwift でストリームの購読処理を行う際にラベル・引数ともに省略すると
onNext
とonDisposed
で同じクロージャが処理される-
onNext
とonDisposed
が同じクロージャの形式になるためか? -
詳細な原因は今のところ不明 - メソッドが
subscribe(_ on:)
に変化してしまうため
-
-
.take(1)
などで一度だけ処理する場合、一度onNext
イベントが流れると購読が disposed されるためonCompleted
イベントが続けて流れるため 予期せず2回処理が走ってしまう - ラベル・値のどちらかを省略せず書くことで問題を回避可能
- コード補完機能に従ってコーディングすると自然とラベルを省略しがちなので注意が必要
Author And Source
この問題について(【RxSwift】subscribe 時に省略系を用いると onNext と onDisposed で同じクロージャが処理されたように見える), 我々は、より多くの情報をここで見つけました https://qiita.com/m-inada0408/items/73c1130f765cbc324da4著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .