#はじめに
前回
今回はclosure, delegate, RxSwiftでカウンターアプリを作ってみました。
#GitHub
CounterRxSwiftにあります。
#実装
大切なのは、RxSwiftを使った場合なので、そこの解説だけしておきたいと思います。
まず、こちらを参考にRxSwiftViewController.xib
という.xib
で初期起動するようにしてください。
そして、以下のようにラベルとボタンをそれぞれ配置します。(stackViewを使うといいと思います)
以下のような手順で作ります。
1.InputとOutputを作る
2.ViewModelを作る
3.ViewControllerを作成
です。
1.InputとOutputを作る
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を作る
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を作成
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を自動で更新させている)
・デメリット
→コード量が多い
→書き方に慣れるまで時間がかかる
#おわりに
次回
少しずつわかってきました!