LoginSignup
1
2

More than 3 years have passed since last update.

【Swift】RxSwift勉強してみたPart5

Last updated at Posted at 2021-04-05

はじめに

前回
今回はclosure, delegate, RxSwiftでカウンターアプリを作ってみました。

GitHub

CounterRxSwiftにあります。

実装

大切なのは、RxSwiftを使った場合なので、そこの解説だけしておきたいと思います。
まず、こちらを参考にRxSwiftViewController.xibという.xibで初期起動するようにしてください。
そして、以下のようにラベルとボタンをそれぞれ配置します。(stackViewを使うといいと思います)
スクリーンショット 2021-04-05 21.34.56.png

以下のような手順で作ります。
1.InputとOutputを作る
2.ViewModelを作る
3.ViewControllerを作成
です。

1.InputとOutputを作る

CounterViewModelInput
import RxSwift
import RxCocoa

protocol CounterViewModelOutput {
    var counterText: Driver<String?> { get }
}

struct CounterViewModelInput {
    let countUpButton: Observable<Void>
    let countDownButton: Observable<Void>
    let countResetButton: Observable<Void>
}

protocol CounterViewModelType {
    var outputs: CounterViewModelOutput? { get }
    func setup(input: CounterViewModelInput)
}

2.ViewModelを作る

RxCounterViewModel

import RxSwift
import RxCocoa

class RxCounterViewModel: CounterViewModelType {

    var outputs: CounterViewModelOutput?
    private let countRelay = BehaviorRelay<Int>(value: 0)
    private let initialCount = 0
    private let disposeBag = DisposeBag()

    init() {
        self.outputs = self
        resetCount()
    }

    func setup(input: CounterViewModelInput) {

        input.countUpButton
            .subscribe(onNext: { [weak self] in
                self?.incrementCount()
            })
            .disposed(by: disposeBag)

        input.countDownButton
            .subscribe(onNext: { [weak self] in
                self?.decrementCount()
            })
            .disposed(by: disposeBag)

        input.countResetButton
            .subscribe(onNext: { [weak self] in
                self?.resetCount()
            })
            .disposed(by: disposeBag)

    }

    private func incrementCount() {
        let count = countRelay.value + 1
        countRelay.accept(count)
    }

    private func decrementCount() {
        let count = countRelay.value - 1
        countRelay.accept(count)
    }

    private func resetCount() {
        countRelay.accept(initialCount)
    }

}

extension RxCounterViewModel: CounterViewModelOutput {

    var counterText: Driver<String?> {
        return countRelay
            .map { String($0) }
            .asDriver(onErrorJustReturn: "")
    }

}

3.ViewControllerを作成

RxSwiftViewController
class RxSwiftViewController: UIViewController {

    @IBOutlet weak var countLabel: UILabel!
    @IBOutlet weak var countUpButton: UIButton!
    @IBOutlet weak var countDownButton: UIButton!
    @IBOutlet weak var countResetButton: UIButton!

    private let disposeBag = DisposeBag()
    private var viewModel = RxCounterViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()

        setupViewModel()        

    }

    private func setupViewModel() {
        let input = CounterViewModelInput(countUpButton: countUpButton.rx.tap.asObservable(),
                                          countDownButton: countDownButton.rx.tap.asObservable(),
                                          countResetButton: countResetButton.rx.tap.asObservable())
        viewModel.setup(input: input)
        viewModel.outputs?.counterText
            .drive(countLabel.rx.text)
            .disposed(by: disposeBag)
    }

}

メリットとデメリット

・メリット
ViewController
→スッキリした
→InputとOutputだけ気にすれば良くなった
ViewModel
→increment decrement resetがデータの処理に集中できた
→ViewControllerのことを意識しなくても良い(delegate(count: count)のようなデータの更新の通知をしなくても良い)
→大きなメリットはViewModelがViewControllerのことを知らなくて良いところ(ViewControllerがViewModelの値を監視して変更があったらUIを自動で更新させている)
・デメリット
→コード量が多い
→書き方に慣れるまで時間がかかる

おわりに

次回
少しずつわかってきました!

1
2
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
1
2