【Xcode/Swift】RxSwiftを使ってシンプルなカウンターアプリを作ってみる

実装

Storyboard

CounterViewModel.swift (ロジック)

import RxSwift
import RxCocoa

protocol CounterViewModelInputs {
    var increment: PublishRelay<Void> { get }
    var decrement: PublishRelay<Void> { get }
    var reset: PublishRelay<Void> { get }
}

protocol CounterViewModelOutputs {
    var counterValue: Driver<Int> { get }
}

protocol CounterViewModelType {
    var inputs: CounterViewModelInputs { get }
    var outputs: CounterViewModelOutputs { get }
}

class CounterViewModel: CounterViewModelType, CounterViewModelInputs, CounterViewModelOutputs {
    var inputs: CounterViewModelInputs { return self }
    var outputs: CounterViewModelOutputs { return self }

    // Inputs
    let increment = PublishRelay<Void>()
    let decrement = PublishRelay<Void>()
    let reset = PublishRelay<Void>()

    // Outputs
    let counterValue: Driver<Int>

    // Properties
    private let _counterValue = BehaviorRelay<Int>(value: 0)
    private let disposeBag = DisposeBag()

    init() {
        increment
            .withLatestFrom(_counterValue)
            .map { $0 + 1 }
            .bind(to: _counterValue)
            .disposed(by: disposeBag)

        decrement
            .withLatestFrom(_counterValue)
            .map { $0 - 1 }
            .bind(to: _counterValue)
            .disposed(by: disposeBag)

        reset
            .map { 0 }
            .bind(to: _counterValue)
            .disposed(by: disposeBag)

        counterValue = _counterValue
            .asDriver(onErrorJustReturn: 0)
            .distinctUntilChanged()
    }
}

HomeViewController.swift (メインのView)

import UIKit
import RxSwift
import RxCocoa

class HomeViewController: UIViewController {

    @IBOutlet private weak var counterLabel: UILabel!
    @IBOutlet private weak var incrementLabel: UIButton!
    @IBOutlet private weak var decrementLabel: UIButton!
    @IBOutlet private weak var resetLabel: UIButton!

    private let viewModel: CounterViewModelType = CounterViewModel()
    private let disposeBag = DisposeBag()

    // MARK: - View Life Cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        bind()
    }

}

private extension HomeViewController {
    func bind() {
        incrementLabel.rx.tap
            .bind(to: viewModel.inputs.increment)
            .disposed(by: disposeBag)

        decrementLabel.rx.tap
            .bind(to: viewModel.inputs.decrement)
            .disposed(by: disposeBag)

        resetLabel.rx.tap
            .bind(to: viewModel.inputs.reset)
            .disposed(by: disposeBag)

        viewModel.outputs.counter
            .map { String($0) }
            .drive(counterLabel.rx.text)
            .disposed(by: disposeBag)
    }
}