##内容
タイマーアプリを作成するためのポイントを複数記事に分けて掲載しています。
この記事では、カウントダウンタイマーで実際に残り時間の表示を1秒毎に更新する手順について掲載します。
##環境
- OS: macOS 10.15.7 (Catalina)
- エディタ: Xcode 12.1
- 言語: Swift
- 主な使用ライブラリ: SwiftUI
##Gitリポジトリ
以下のGitリポジトリのURLからサンプルコードをご覧いただけます。
https://github.com/msnsk/Qiita_Timer.git
##手順
- TimeManager クラスに Timer クラス publish メソッドを追加する
- MainView の残り時間の表示を1秒毎に更新する
###1. TimeManager クラスに Timer クラス publish メソッドを追加する
現時点では、スタートボタンを押しても、タイマーステータスは .running に変わりますが、画面上はまだ残り時間がカウントダウンされません。画面上は Picker で設定した時間のまま止まっています。
そこで、このタイマーアプリの肝となる残り時間のカウントダウン表示を実装していきます。
SwiftUI ライブラリにも含まれますが、Swift 言語の一番ベースとなる Foundation ライブラリに用意されている Timer というクラスの publish というメソッドを利用します。
以下のように記述することで、publish メソッドの引数 every で指定した時間(1秒)ごとに発動するタイマーを変数 timer に格納します。これを View 側で利用することで、何らかのアクションを1秒毎に発動したいときにトリガーになってくれます。ここでは、タイマーアプリが残り時間を1秒毎に更新する際にトリガーとして利用していきます。
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 に変更するように記述します。
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
}
}
}
}
これでようやくカウントダウンタイマーらしくなってきました。
次回は、アラームの実装をしていきます。