【Swift】RxSwift勉強してみたPart5

#はじめに
[前回](https://qiita.com/REON/items/c986ff93e67e3693324c)
今回はclosure, delegate, RxSwiftでカウンターアプリを作ってみました。

#GitHub
CounterRxSwiftにあります。

https://github.com/0429oonishi/RxSwifts

#実装
大切なのは、RxSwiftを使った場合なので、そこの解説だけしておきたいと思います。
まず、[こちら](https://qiita.com/REON/items/1c591b6f4f570b773fb2)を参考に`RxSwiftViewController.xib`という`.xib`で初期起動するようにしてください。
そして、以下のようにラベルとボタンをそれぞれ配置します。(stackViewを使うといいと思います)
![スクリーンショット 2021-04-05 21.34.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/ef1a22ef-efc5-27ac-0a48-231dca85c729.png)

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

1.InputとOutputを作る

```swift: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を作る

```swift: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を作成

```swift: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を自動で更新させている)
・デメリット
→コード量が多い
→書き方に慣れるまで時間がかかる

#おわりに
[次回](https://qiita.com/REON/items/8fd68bb59c0e6dbdbc3f)
少しずつわかってきました!