#はじめに
- RxSwiftの導入を検討している。
- Swiftで書いてきたけれど、RxSwiftもこれから使っていきたい。
と言ったRxSwift初心者向けの記事です。
RxSwiftを使って簡単なデータバインディングのサンプルを作成します。
#この記事のゴール
この記事では、ViewControllerとViewModelの値をbindさせて、UITextFieldが更新されたら、UILabelが更新されるサンプルを作成します。
ViewControllerとViewModel間でデータバインディングを行なって、値が更新されたらViewが更新します。
#下準備
Xcodeで新規プロジェクトを作成して、RxSwiftとRxCocoaをインポートします。
##RxSwiftとRxCocoaをインポートする
こちらの記事を参考にRxSwiftをプロジェクトにインポートしてください。
#Viewの準備
まずStoryBoardにUITextFieldとUILabelを置いて、ViewControllerに紐付けます。
import UIKit
class ViewController: UIViewController {
@IBOutlet weak private var textField: UITextField!
@IBOutlet weak private var titleLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
#TextFieldの更新を監視
続いてTextFieldが入力を監視するコードをViewControllerに追加します。
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
@IBOutlet weak private var textField: UITextField!
@IBOutlet weak private var titleLabel: UILabel!
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
bind()
}
private func bind() {
textField.rx.text.orEmpty.asObservable()
.subscribe { [weak self] in
// ここでViewModelに値の更新を通知します。
}
.disposed(by: disposeBag)
}
}
#ViewModelで対象の値の作成
import RxSwift
class ViewModel {
var title: Observable<String> {
return titleSubject
}
private let titleSubject = PublishSubject<String>()
}
監視対象の変数を作成して、管理をします。
対象となるtitleSubjectは、外から更新できないようにカプセル化します。
#ViewControllerで値を受け取るコードを追加
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
@IBOutlet weak private var textField: UITextField!
@IBOutlet weak private var titleLabel: UILabel!
private let viewModel = ViewModel()
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
bind()
}
private func bind() {
textField.rx.text.orEmpty.asObservable()
.subscribe { [weak self] in
// ここでViewModelに値の更新を通知します。
}
.disposed(by: disposeBag)
viewModel.title.asObservable()
.subscribe { [weak self] in
// ここでViewModelの更新を受け取ります。
}.disposed(by: disposeBag)
}
}
#ViewControllerからVideModelの値を更新する
ViewModelの管理対象はカプセル化していますので、新しく関数を作って値の更新を行います。
private func bind() {
textField.rx.text.orEmpty.asObservable()
.subscribe { [weak self] in
guard let value = $0.element else { return }
self?.viewModel.set(text: value)
}
.disposed(by: disposeBag)
viewModel.title.asObservable()
.subscribe { [weak self] in
// ここでViewModelの更新を受け取ります。
}.disposed(by: disposeBag)
}
import RxSwift
class ViewModel {
var title: Observable<String> {
return titleSubject
}
private let titleSubject = PublishSubject<String>()
func set(text: String) {
titleSubject.onNext(text)
}
}
これでViewControllerからVideModelの監視された値を更新することができました。
#ViewModelの更新を受け取ってViewを更新する
ViewModelの更新をすることができました。
最後に先ほど作成したViewModelの値の更新を受け取るコードの中に、Viewを更新するコードを追加します。
private func bind() {
textField.rx.text.orEmpty.asObservable()
.subscribe { [weak self] in
guard let value = $0.element else { return }
self?.viewModel.set(text: value)
}
.disposed(by: disposeBag)
viewModel.title.asObservable()
.subscribe { [weak self] in
self?.titleLabel.text = $0.element
}.disposed(by: disposeBag)
}
簡単にUITextFieldとUILabelのデータをバインディングすることができました。
#サンプルコード
https://github.com/hananao/RxSwift_Begin_Sample_UITextField_UILabel
#まとめ
細かい部分の説明は不十分ですが、簡単にRxSwiftを使ってデータバインディングすることができました。
記事について間違っている部分やご指摘などありましたら、コメントにお願いします。