LoginSignup
4
3

More than 3 years have passed since last update.

iOSアプリ開発:タイマーアプリ(4.カウントダウンの実装)

Last updated at Posted at 2020-10-19

スクリーンショット 2020-10-28 10.44.31.png

内容

タイマーアプリを作成するためのポイントを複数記事に分けて掲載しています。
この記事では、カウントダウンタイマーで実際に残り時間の表示を1秒毎に更新する手順について掲載します。

環境

  • OS: macOS 10.15.7 (Catalina)
  • エディタ: Xcode 12.1
  • 言語: Swift
  • 主な使用ライブラリ: SwiftUI

Gitリポジトリ

以下のGitリポジトリのURLからサンプルコードをご覧いただけます。
https://github.com/msnsk/Qiita_Timer.git

手順

  1. TimeManager クラスに Timer クラス publish メソッドを追加する
  2. MainView の残り時間の表示を1秒毎に更新する

1. TimeManager クラスに Timer クラス publish メソッドを追加する

現時点では、スタートボタンを押しても、タイマーステータスは .running に変わりますが、画面上はまだ残り時間がカウントダウンされません。画面上は Picker で設定した時間のまま止まっています。

そこで、このタイマーアプリの肝となる残り時間のカウントダウン表示を実装していきます。

SwiftUI ライブラリにも含まれますが、Swift 言語の一番ベースとなる Foundation ライブラリに用意されている Timer というクラスの publish というメソッドを利用します。

以下のように記述することで、publish メソッドの引数 every で指定した時間(1秒)ごとに発動するタイマーを変数 timer に格納します。これを View 側で利用することで、何らかのアクションを1秒毎に発動したいときにトリガーになってくれます。ここでは、タイマーアプリが残り時間を1秒毎に更新する際にトリガーとして利用していきます。

TimeManager.swift
class TimeManager: ObservableObject {
    //(他のプロパティ省略)

    //1秒ごとに発動するTimerクラスのpublishメソッド
    var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    //(メソッド省略)
}

2. MainView の残り時間の表示を1秒毎に更新する

MainView で TimerView を含んでいる一番外側の ZStack に .onReceive モディファイアを追加します。ZStack 内のすべてのViewに反映されます。

この.onReceive モディファイアが TimeManager クラスの timer の1秒毎の発動を受けとります。そして、そのあとのクロージャには timer 発動ごとに実行するコードを記述します。

guard let ~ else 構文で、タイマーステータスが.running 以外の時は何も実行しないようにクロージャには return を記述します。
タイマーステータスが.running であれば、それ以下のif文へ進みます。

if文では、残り時間が 0 より大きい時は、残り時間から1秒引き算し、残り時間が0以下の場合は、タイマーステータスを .stopped に変更するように記述します。

MainView.swift
struct MainView: View {
    @EnvironmentObject var timeManager: TimeManager

    var body: some View {
        ZStack {
            if timeManager.timerStatus == .stopped {
                PickerView()
            } else {
                TimerView()
            }

            VStack {
                Spacer()
                ButtonsView()
                    .padding(.bottom)
            }
        }
        //指定した時間(1秒)ごとに発動するtimerをトリガーにしてクロージャ内のコードを実行
        .onReceive(timeManager.timer) { _ in
            //タイマーステータスが.running以外の場合何も実行しない
            guard self.timeManager.timerStatus == .running else { return }
            //残り時間が0より大きい場合
            if self.timeManager.duration > 0 {
                //残り時間から -1 する
                self.timeManager.duration -= 1
                //残り時間が0以下の場合
            } else {
                //タイマーステータスを.stoppedに変更する
                self.timeManager.timerStatus = .stopped
            }
        }
    }
}

これでようやくカウントダウンタイマーらしくなってきました。
次回は、アラームの実装をしていきます。

4
3
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
4
3