#はじめに
前回
今回も教えていただいたことをまとめていこうと思います。
#実装
ViewController
import UIKit
import RxSwift
import RxCocoa
final class ViewController: UIViewController {
@IBOutlet private weak var textField: UITextField!
@IBOutlet private weak var button: UIButton!
@IBOutlet private weak var label: UILabel!
private let disposeBag = DisposeBag()
private var viewModel: ViewModelType = ViewModel()
override func viewDidLoad() {
super.viewDidLoad()
// MARK: - Input
//bindでViewModelにイベントを送るパターン
textField.rx.text.orEmpty
.bind(to: viewModel.inputs.text)
.disposed(by: disposeBag)
//onNextで送るパターン
button.rx.tap
.subscribe { _ in
self.viewModel.inputs.text.onNext("タップ")
}
.disposed(by: disposeBag)
// MARK: - Output
//viewModelからoutputをUIパーツにbindするパターン
viewModel.outputs.validText
.bind(to: label.rx.text)
.disposed(by: disposeBag)
}
}
ViewModel
import RxSwift
import RxCocoa
protocol ViewModelInput {
//読み取り専用にしたいため、AnyObserver
var text: AnyObserver<String> { get }
}
protocol ViewModelOutput {
//ViewでsubsrcibeするためにObservable
var validText: Observable<String> { get }
}
protocol ViewModelType {
var inputs: ViewModelInput { get }
var outputs: ViewModelOutput { get }
}
class ViewModel: ViewModelInput, ViewModelOutput {
var text: AnyObserver<String>
var validText: Observable<String>
init() {
let _validText = PublishRelay<String>()
self.validText = _validText.asObservable()
self.text = AnyObserver<String>() { text in
//viewからイベントを受け取り、加工したものをoutputにaccept
let validText = text.element!
_validText.accept(validText)
}
}
}
extension ViewModel: ViewModelType {
var inputs: ViewModelInput {
return self
}
var outputs: ViewModelOutput {
return self
}
}
#イベントの送り方受け取り方
###Input(View -> ViewModel)
今回はボタンを押した時とテキストフィールドに文字が入力された時にイベントを流します。
以下はbindでviewModelのinputのtextにイベントを送っています。
textField.rx.text.orEmpty
.bind(to: viewModel.inputs.text)
.disposed(by: disposeBag)
こちらはボタンのイベントをviewModelのinputのtextにonNextで送っています。
button.rx.tap
.subscribe { _ in
self.viewModel.inputs.text.onNext("タップ")
}
.disposed(by: disposeBag)
そして、ViewModelのViewModelInputプロトコルに送るtextを定義しておいて、加工してoutputで返すという流れです。
protocol ViewModelInput {
var text: AnyObserver<String> { get }
}
###Output(ViewModel -> View)
イニシャライザ内で値を加工し、acceptでoutputにイベントを送ります。
class ViewModel: ViewModelInput, ViewModelOutput {
var text: AnyObserver<String>
var validText: Observable<String>
init() {
let _validText = PublishRelay<String>()
self.validText = _validText.asObservable()
self.text = AnyObserver<String>() { text in
let validText = text.element!
_validText.accept(validText)
}
}
}
viewModelから送られてきたoutputをbindすることで、labelに反映させる。
viewModel.outputs.validText
.bind(to: label.rx.text)
.disposed(by: disposeBag)
#おわりに
少しずつ分かってきましたね!