
Swiftの非同期処理(Concurrency)を使ってアプリをよりスムーズにしたいとき、「一定時間待つ」「時間の長さを測る」といった処理はとてもよく出てきます。
そんなときに使えるのが ContinuousClock(コンティニュアスクロック)という時計の仕組みです。
一見、Timerと似ていそうに見えますが、Swiftの新しい非同期スタイル(async/await)ととても相性が良く、より柔軟でテストしやすくなっています。
この記事では、ContinuousClock の使い方や具体例、Timer.scheduledTimerとの違い、活用できる場面までをわかりやすく解説します。
ContinuousClockとは?
ContinuousClock とは、「常に流れ続ける時間」に基づいて動作する時計です。
たとえば、iPhone の電源を入れてから現在までに経過した時間を基準にして動きます。
アプリがスリープしたり、画面が閉じられたりしても止まらずに時間が進み続けるのが特徴です。
この ContinuousClock は、Swift 標準ライブラリに用意されている 構造体(struct) です。
クラスではなく構造体であるため、値型として扱われ、コピーしても独立して動作します。
そのため、複数の場所で同じ ContinuousClock を利用しても、それぞれが共通の「連続した時間」を参照するだけで、参照共有やメモリ管理を意識する必要がありません。
さらに、大きなポイントとして、Swift の非同期処理(async/await)と組み合わせて使えるように設計されている点です。
待機処理や時間制御をシンプルに記述できるのもContinuousClockの利点です。
基本的な使い方
基本的な使い方として、ContinuousClock を使えば「一定時間待ってから処理を実行する」といったことが簡単にできます。
例えば、次のコードでは「2秒待ってからメッセージを変更する」という動きを実現しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
struct ContentView: View { @State private var message = "まだ待機していません" var body: some View { VStack(spacing: 20) { Text(message) .font(.headline) Button("2秒待機する") { Task { // 2秒待機 try? await ContinuousClock().sleep(for: .seconds(2)) message = "2秒経過しました!" } } } .padding() } } #Preview { ContentView() } |
コードのポイント
@State private var message = "まだ待機していません"
→ 画面に表示するメッセージを保持するための変数です。最初は「まだ待機していません」と表示されます。Button("2秒待機する") { ... }
→ ボタンを押すと、中の処理が実行されます。Task { ... }
→ Swift の 非同期処理 を使うためにTaskを作成しています。この中でawaitを使えるようになります。try? await ContinuousClock().sleep(for: .seconds(2))
→ ContinuousClock を使って「2秒待つ」処理をしています。ここでアプリ全体が止まるわけではなく、非同期的に「待機」するだけなので、他の処理は並行して動き続けます。message = "2秒経過しました!"
→ 2秒経過したあと、表示するメッセージが変更され、画面に反映されます。
つまり、このコードは ボタンを押す → 2秒待機 → メッセージが変わる という流れを、ContinuousClock を使ってシンプルに書けるサンプルです。

処理にかかる時間を測る
ContinuousClock は「待機」だけでなく、処理にかかる時間を測定する用途にも使えます。
measure {} を使うと、ある処理がどれくらいの時間を要したかを簡単に計測できます。
|
1 2 3 4 5 6 7 8 |
let clock = ContinuousClock() let duration = clock.measure { for _ in 0..<1_000_000 { _ = UUID().uuidString } } print("処理にかかった時間: \(duration)") |
コードのポイント
let clock = ContinuousClock()
→ 計測に使う時計(ContinuousClock)を用意します。clock.measure { ... }
→{ ... }の中に実行したい処理を書きます。ここでは 100万回のループで UUID を文字列に変換する 処理を入れています。let duration = ...
→ 処理にかかった時間がdurationに格納されます。この値はDuration型 です。print("処理にかかった時間: \(duration)")
→ 実際にどれくらい時間がかかったのかをコンソールに出力します。
つまり、ContinuousClock を使えば「何秒待つか」だけでなく、「処理に何秒かかったか」までシンプルに測定できるわけです。
主要なメソッド
ContinuousClock が提供する主な機能は以下の2つです。
1. sleep(for:)
指定した時間だけ非同期的に待機します。
引数は Duration 型(.seconds、.millisecondsなど)で指定します。
|
1 2 |
try await clock.sleep(for: .seconds(2)) |
ポイント:
- UIを止めずに自然に待機できる
- キャンセル可能(Task.cancel()で中断できる)
- スリープやバックグラウンドでも時間は進み続ける
2. measure {}
任意の処理にかかる時間を測って、Duration型で返します。
|
1 2 3 4 |
let duration = clock.measure { // 時間のかかる処理 } |
ポイント:
- 関数全体の処理時間を簡単に測れる
- テストやベンチマークに便利
これらのメソッドに共通するのは、Swift標準の Duration 型と組み合わせて使う設計になっており、「時間」にまつわる処理を統一的に扱えることです。
活用シーン
ContinuousClock は、単に「待機」や「計測」に使えるだけでなく、実際のアプリ開発で幅広く活用できます。
特に Swift の非同期処理(async/await)と組み合わせることで、UI を止めずに自然な時間制御を実現できるのが大きな利点です。
- 非同期処理の間に一定時間待つ(例:API の再試行まで 1 秒間待つ)
- 時計のように一定時間ごとに何か処理したい(例:UI の定期更新)
- 時間がかかる処理のベンチマーク測定
- Task ベースで動作していて、UI を止めずに待機したい場面
このように、ContinuousClock は「正確な時間制御」と「非同期処理との相性の良さ」を両立しているため、実用的な場面で非常に役立つ機能です。
Timer.scheduledTimerとの違い
ContinuousClock を理解するうえで、従来よく使われてきた Timer.scheduledTimer との違いを押さえておくことはとても重要です。
ContinuousClock は Swift Concurrency と統合されており、非同期処理の流れに自然に組み込めます。
一方、Timer.scheduledTimer は UIKit 由来の仕組みであり、古くから使われている方法です。
そのため設計思想や使い勝手に大きな違いがあります。
| 比較項目 | ContinuousClock | Timer.scheduledTimer |
|---|---|---|
| 時間の指定方法 | Duration 型(.seconds など) | 秒数(Double) |
| 非同期(async/await)対応 | 完全対応 | 非同期では使えない |
| 処理の中断(キャンセル) | Task.cancel() などで可能 | 自前で管理する必要あり |
| 精度 | 高い(システム時間を元に) | やや低め(スリープ中は止まる) |
| UIスレッドとの分離 | UIをブロックしない | 実装によってはUIをブロックする |
| 可読性・保守性 | モダン(新しいSwiftスタイル) | レガシー寄り(UIKit由来) |
つまり、ContinuousClock は Swift のモダンな非同期コードと相性が良く、より安全で柔軟です。
逆に、Timer.scheduledTimer は古くからある方式で、非同期タスクではやや使いにくく、UIとの連携も工夫が必要になります。
注意点
ContinuousClock は便利で柔軟に使える一方で、実際にアプリへ組み込む際にはいくつか注意すべきポイントがあります。
特に非同期処理や SwiftUI と組み合わせるときには、設計段階で意識しておくと安全です。
sleep(for:)は 非同期関数 なので、try awaitを忘れずに書く- SwiftUI で使う場合は
ObservableObjectと@MainActorを併用すると状態管理が安全 - 非同期ループを使うときは キャンセル処理 を考慮する(特に
Task.cancel()) - 時間の間隔が短すぎると バッテリー消費 や UI パフォーマンス低下 の原因になる
これらを意識して使えば、ContinuousClock は「正確な時間制御」と「モダンな非同期処理」の両方を活かせる便利なツールになります。
まとめ
今回紹介した ContinuousClock は、「常に流れ続ける時間」に基づいて動作する Swift 標準ライブラリの新しい時計です。
- Swift の 非同期処理(async/await) と組み合わせやすい
- 一定時間の待機 や 処理時間の測定 がシンプルに書ける
Timer.scheduledTimerよりも モダンで安全、しかも テストしやすい- SwiftUI とも相性が良く、UI をブロックせずに自然な時間制御ができる
従来は Timer を使っていた場面も、これからは ContinuousClock に置き換えることで、より洗練された Swift コードを書くことが可能になります。
ぜひ日常の開発に取り入れて、モダンな Swift コードのメリットを実感してみてくださいね!


