【Swift】Timer.scheduledTimerとは?使い方や引数の意味、活用シーンをわかりやすく解説!

一定時間ごとに処理を繰り返したいときに便利なのが Timer.scheduledTimer です。

アニメーションの更新、定期的なデータ取得、UIのカウントダウン表示など、様々なタイミング制御に活用されます。

SwiftUIでは、UIKitと異なりViewのライフサイクルに注意する必要があります。

この記事では、SwiftUIでのTimer.scheduledTimerの基本的な使い方から、引数の意味、活用シーン、注意点までをわかりやすく解説します。

Timer.scheduledTimerとは?

Timer.scheduledTimer は、一定の間隔で処理を繰り返すタイマーを作成し、自動的に現在のRunLoopに追加してくれます。

従来の Timer(timeInterval:target:selector:repeats:) に比べて、ブロックで直接処理を書けるため、より簡潔で安全に記述できます。

ただし、SwiftUIのViewの中で直接呼ぶのではなく、状態管理(@StateObject / @ObservableObject)や.onAppearなどに組み込むのが基本になります。

基本の使い方

以下のようにonAppear内でタイマーを起動し、状態変数を更新します。

このコードでは、onAppearでタイマーを起動し、onDisappearで必ず停止するようにして、メモリリークや余計な処理を防いでいます。

Timer.scheduler

具体例:スタートボタンでタイマーを開始する

ユーザー操作で明示的にタイマーを開始したい場合は、ボタンと組み合わせることができます。

これにより、ユーザーが「スタート」を押したときにカウントアップが始まり、「ストップ」を押すと終了します。

繰り返しをしない例(1回だけ)

主要な引数とその意味

Timer.scheduledTimer を正しく活用するためには、それぞれの引数の役割を理解することが重要です。

まず、このメソッドのシグネチャ(イニシャライザーに相当する呼び出し形式)を確認しておきましょう。

このように、Timer.scheduledTimer時間間隔(interval)・繰り返し有無(repeats)・実行内容(block) の3つを指定するだけでシンプルに使える設計になっています。

引数名 説明
withTimeInterval TimeInterval(Double) タイマーが発火する間隔(秒数)を指定します。
例えば 1.0 とすれば1秒ごとに処理が呼ばれます。ミリ秒単位で細かい制御も可能です。
repeats Bool 繰り返すかどうかを指定します。
true なら指定した間隔ごとに繰り返し処理が走り、false なら一度だけ実行されます。
block (Timer) -> Void タイマー発火時に実行されるクロージャ(処理の中身)を定義します。
クロージャには呼び出し元の Timer インスタンスが渡されるので、処理の中で invalidate() を呼んで停止させることも可能です。

つまり、「いつ実行するか(withTimeInterval)」「何回実行するか(repeats)」「何を実行するか(block)」 の3点を指定するだけで、シンプルに時間制御を組み込めます。

また、block 内で timer.invalidate() を呼ぶことで、必要に応じて実行中のタイマーを止められる点も実務上よく使われます。

活用シーン

Timer.scheduledTimer はユーザー体験の改善やバックグラウンド処理に役立ちます。

代表的な活用シーンは以下の通りです。

  • カウントダウンタイマーの実装
    例:試験やクイズアプリで残り時間を表示する。
  • 一定間隔でのUI更新(進捗バーなど)
    例:処理の進捗を視覚的に伝えるアニメーション更新。
  • バックエンドへの定期的なポーリング
    例:一定時間ごとにサーバーへリクエストを投げて新着データを確認。
  • アニメーションのトリガー
    例:数秒ごとに画像を切り替えるスライドショー。
  • ユーザーの無操作検出(インアクティブ監視)
    例:数分間操作がない場合に警告やスクリーンセーバーを起動。

このように、UIまわりからバックエンド処理まで幅広く利用可能で、アプリに「時間的な動き」を加えるうえで欠かせない仕組みです。

注意点

非常に便利な一方で、設計を誤るとメモリリークや意図しない処理が残り続けるリスクがあります。

利用時には次のポイントに注意してください。

  • RunLoopへの登録に依存する
    タイマーはRunLoopに登録されるため、スレッドが止まっていると動作しません。通常はメインスレッドで十分ですが、バックグラウンドタスクでは注意が必要です。
  • SwiftUIのライフサイクルとの整合性
    View が破棄されてもタイマーが残り続けることがあります。onDisappear で必ず invalidate() を呼び、不要なタイマーを終了させましょう。
  • 強参照サイクル(retain cycle)の回避
    クロージャ内で self をそのまま使うと強参照が発生し、インスタンスが解放されなくなります。必ず [weak self] を使って循環参照を避けましょう。
  • 用途に応じた代替手段の検討
    高精度なタイミング制御やSwift Concurrencyとの相性を考えると、DispatchSourceTimerTask.sleep を選んだ方がよい場合もあります。

「どこで」「どのように」タイマーを管理するかを意識しないと、予期せぬ挙動やパフォーマンス低下の原因になりかねないので、その点は注意が必要です。

まとめ

Timer.scheduledTimer はSwiftUIでも利用可能ですが、Viewライフサイクルに応じた管理が必須です。

  • 一定時間ごとに処理を実行できる
  • クロージャで直接記述できるためコードが簡潔
  • onAppear / onDisappear またはボタン操作と組み合わせて安全に管理できる
  • Swift ConcurrencyやCombineベースのアプローチと比較してもシンプルに導入できる

時間制御が必要なアプリ開発では欠かせない仕組みなので、SwiftUIでも正しく扱えるようにしておきましょう!

おすすめの記事