RxSwiftを利用したシンプルなアプリ
RxSwiftの知見を増やすためにアプトプットをしております。よく使われるメソッドを実際に触ってみて動作確認を進めてます。
今回はシンプルなステッパーカウンターアプリを作成しました。
仕様
- 数字を1つ増加させる「+」ボタンとリセットボタンを配置
- +ボタンを押すとLabelに押した分だけ表示され、10回押すとバナーを表示
- リセットボタンを押すと数字がリセットされ、且つバナーも非表示にする
こんな感じです。画像は10回タップしたらバナーが表示された状態。
リセットボタンを押したら0に戻り、バナーも非表示に切り替わります。
コード
ViewModel
import Foundation
import RxSwift
import RxCocoa
protocol ViewModelInputs: AnyObject {
var tapButton: PublishRelay<Void> { get }
var resetButton: PublishRelay<Void> { get }
}
protocol ViewModelOutputs: AnyObject {
var tapCountLabel: Driver<Int> { get }
var isBannerVisible: Driver<Bool> { get }
}
protocol ViewModelType: AnyObject {
var input: ViewModelInputs { get }
var output: ViewModelOutputs { get }
}
class ViewModel: ViewModelInputs, ViewModelOutputs, ViewModelType {
var input: ViewModelInputs { return self }
var output: ViewModelOutputs { return self }
var tapButton = PublishRelay<Void>()
var resetButton = PublishRelay<Void>()
var tapCountLabel: Driver<Int>
var isBannerVisible: Driver<Bool>
var count = BehaviorRelay<Int>(value: 0)
var disposeBag = DisposeBag()
init () {
tapButton
.withLatestFrom(count)
.filter { $0 < 10 }
.map { $0 + 1 }
.bind(to: count)
.disposed(by: disposeBag)
resetButton
.map { _ in 0 }
.bind(to: count)
.disposed(by: disposeBag)
tapCountLabel = count
.asDriver(onErrorJustReturn: 0)
.distinctUntilChanged()
isBannerVisible = tapCountLabel
.map { $0 >= 10 }
.distinctUntilChanged()
}
}
ViewController
import UIKit
import RxSwift
import RxCocoa
final class ViewController: UIViewController {
@IBOutlet private weak var bannerlabel: UILabel!
@IBOutlet private weak var counterlabel: UILabel!
@IBOutlet private weak var countUpButton: UIButton!
@IBOutlet private weak var resetButton: UIButton!
let viewModel = ViewModel()
let disposedBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
bind()
}
}
extension ViewController {
func bind() {
countUpButton.rx.tap
.bind(to: viewModel.input.tapButton)
.disposed(by: disposedBag)
resetButton.rx.tap
.bind(to: viewModel.input.resetButton)
.disposed(by: disposedBag)
viewModel.output.tapCountLabel
.map { String($0) }
.drive(counterlabel.rx.text)
.disposed(by: disposedBag)
viewModel.output.isBannerVisible
.map { !$0 }
.drive(bannerlabel.rx.isHidden)
.disposed(by: disposedBag)
}
}
RxSwiftを利用することでボタンなどいちいちIBAction@の紐付けを行う必要もないですし、コードがシンプルになりコードの可読性も上がりました。
学習コストが高く私はまだまだ知識が浅いですが、実際に使ってみるのが一番理解できるなと感じます。
今後はよく利用するメソッドのアウトプットをできればと思います。
参考記事