LoginSignup
2
1

More than 1 year has passed since last update.

【RxSwift】残り時間をセットして自動発火させる実装

Last updated at Posted at 2022-03-30

はじめに

タイマーをセットして時間経過後に一度きりの自動発火処理をRxSwiftを使って実装しました。

環境

Xcode 13.3
Swift 5.6
RxSwift 6.2.0

実装方法の確認

👇の公式ドキュメントを確認しました。

interval(_ period: RxTimeInterval, scheduler: SchedulerType)

intervalを使うことで自動発火の処理が簡単に実現できそうですが、これだと継続的に発火処理が実行されるようです。

Timer.swift

extension ObservableType where Element: RxAbstractInteger {
    /**
     指定されたスケジューラを使ってタイマーを実行し、オブザーバー・メッセージを送信することで、各期間の後に値を生成する観測可能なシーケンスを返します。
     - パラメータ period: 結果のシーケンスに含まれる値を生成する期間。
     - パラメータ scheduler: タイマーを実行するスケジューラ。
     - 戻り値 各期間の後に値を生成する観測可能なシーケンス。
     */
    public static func interval(_ period: RxTimeInterval, scheduler: SchedulerType)
        -> Observable<Element> {
        return Timer(
            dueTime: period,
            period: period,
            scheduler: scheduler
        )
    }
}

timer(_ dueTime: RxTimeInterval, period: RxTimeInterval? = nil, scheduler: SchedulerType)

timerを使うことで一度きりの自動発火の処理が実現できそうです。ただし、periodのパラメータを指定した場合は、継続的に自動発火されてしまうのでdueTimeのみの指定で使っていきます。

Timer.swift
extension ObservableType where Element: RxAbstractInteger {
    /**
     指定された相対的な初期期日が経過した後、指定されたスケジューラでタイマを実行し、定期的に値を生成する観測可能なシーケンスを返します。
     - パラメータ dueTime: 最初の値を生成する相対時間。
     - パラメータ period: 後続の値を生成する期間。
     - パラメータ scheduler: タイマーを実行するスケジューラ。
     - リターン。時間経過後、期間ごとに値を生成する観測可能なシーケンス。
     */
    public static func timer(_ dueTime: RxTimeInterval, period: RxTimeInterval? = nil, scheduler: SchedulerType)
        -> Observable<Element> {
        return Timer(
            dueTime: dueTime,
            period: period,
            scheduler: scheduler
        )
    }
}

上のメソッド内で返しているTimerの中は👇

Timer.swift
final private class Timer<Element: RxAbstractInteger>: Producer<Element> {
    fileprivate let scheduler: SchedulerType
    fileprivate let dueTime: RxTimeInterval
    fileprivate let period: RxTimeInterval?

    init(dueTime: RxTimeInterval, period: RxTimeInterval?, scheduler: SchedulerType) {
        self.scheduler = scheduler
        self.dueTime = dueTime
        self.period = period
    }

    override func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
        if self.period != nil {
            let sink = TimerSink(parent: self, observer: observer, cancel: cancel)
            let subscription = sink.run()
            return (sink: sink, subscription: subscription)
        }
        else {
            let sink = TimerOneOffSink(parent: self, observer: observer, cancel: cancel)
            let subscription = sink.run()
            return (sink: sink, subscription: subscription)
        }
    }
}

以上より、今回はObservableTypetimerを使ってObservableを生成、それをsubscribeしていこうと思います。

実装

GameViewModel
        playModeAutoisSet.subscribe(onNext: { [weak self] time in
            guard let self = self else { return }
            if let timer = self.autoPlayModeTimer {
                timer.dispose()
            }
            self.showMessage.onNext(String(time) + ALERT_AUTO_PLAY_MODE_ON)
            // ここから
            self.autoPlayModeTimer = Observable<Int>
                .timer(DispatchTimeInterval.seconds(time * 60), scheduler: MainScheduler.instance)
                .subscribe { _ in
                    // ここに処理を書く
                    if self.playModeAuto.value != false {
                        self.playModeAuto.accept(false)
                        self.playModeB.accept(true)
                        self.playModeBisChanged.onNext(true)
                        self.showMessage.onNext(ALERT_AUTO_PLAY_MODE_CHANGED)
                    }
                }
            // ここまで
        }).disposed(by: disposeBag)

これで動作確認したところ、無事一度きりの自動発火が実現できました👏

おわりに

簡単なことでしたが、公式ドキュメントを確認することで少し理解が深まった気がします。

参考

2
1
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
2
1