LoginSignup
2
4

More than 3 years have passed since last update.

【Swift】RxSwiftをTwitterで知り合った人に教えてもらったPart2

Posted at

はじめに

前回
今回も教えていただいたことをまとめていこうと思います。

実装

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)

おわりに

少しずつ分かってきましたね!

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4