0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Swift]RxSwift ステップカウンターアプリを作ってみた

Last updated at Posted at 2024-09-05

RxSwiftを利用したシンプルなアプリ

RxSwiftの知見を増やすためにアプトプットをしております。よく使われるメソッドを実際に触ってみて動作確認を進めてます。
今回はシンプルなステッパーカウンターアプリを作成しました。

仕様

  1. 数字を1つ増加させる「+」ボタンとリセットボタンを配置
  2. +ボタンを押すとLabelに押した分だけ表示され、10回押すとバナーを表示
  3. リセットボタンを押すと数字がリセットされ、且つバナーも非表示にする

こんな感じです。画像は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@の紐付けを行う必要もないですし、コードがシンプルになりコードの可読性も上がりました。
学習コストが高く私はまだまだ知識が浅いですが、実際に使ってみるのが一番理解できるなと感じます。
今後はよく利用するメソッドのアウトプットをできればと思います。

参考記事

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?