CloudKit やコールバック API を Swift の async/await(構造化並行性) として扱うためには、両者の仕組みの違いを埋める必要があります。本記事では、その中心的役割を担う withCheckedThrowingContinuation { continuation in } の動きを解説します。
1. まずは async/await と callback の違い
CloudKit のような従来の API は、
処理が終わったら クロージャを呼ぶ(callback 型)。
一方で Swift Concurrency の async/await は、
処理完了まで待ち、戻り値で結果を受け取る(構造化並行性)。
この 2 つは直接互換性がないため、ギャップを埋める仕組みが必要になります。
2. withCheckedThrowingContinuation について
withCheckedThrowingContinuation は、内部で次のような処理をしています。
- async 関数を一時停止させる
- 再開用のハンドル(continuation 詳細は後述)を生成する
- その continuation を
{ continuation in }の引数として渡す - resume が呼ばれるまで待機する
withCheckedThrowingContinuationは、CloudKit のような callback ベース API を 「async/await(構造化並行性)に変換するための通訳」として動作します。
3. continuation について
continuation は、async 関数が一度「停止(suspend)」した状態から、次の 2 パターンのいずれかで再開させるためのハンドルです。
- continuation.
resume(returning: value):成功として再開 - continuation.
resume(throwing: error):失敗として再開
continuation は、「中断された async の return/throw を外部から実行するリモコン」だと言えます。
4. continuation を使った CloudKit の async 化の流れ
例えば CloudKit クエリを async 化した処理は次のようになります。
/// CloudKit から SNSタイムラインの投稿(Post) レコードを取得する非同期メソッド。
func fetchPosts() async throws -> [Post] {
return try await withCheckedThrowingContinuation { continuation in
var posts: [Post] = []
// 「Post レコードを取得する」ための CloudKit クエリ。
// predicate は例として全件取得(true)を指定。
let query = CKQuery(recordType: "Post", predicate: NSPredicate(value: true))
let operation = CKQueryOperation(query: query)
// レコード1件ごとに呼ばれるコールバック時の処理を定義
operation.recordMatchedBlock = { _, result in
if case .success(let record) = result,
let post = try? Post(record: record) {
posts.append(post)
}
}
// クエリ全体が完了したときに 1 回だけ呼ばれるコールバック時の処理を定義
operation.queryResultBlock = { result in
switch result {
case .success:
continuation.resume(returning: posts)
case .failure(let error):
continuation.resume(throwing: error)
}
}
// 非同期クエリを開始する。(コールバックがあるまで処理を中断)
database.add(operation)
}
}
CloudKit(callback)→ continuation.resume() → async(構造化並行性) という流れで結果が受け渡されます。
5. まとめ
- callback API と async/await はアーキテクチャが異なる
- continuation は async の「再開スイッチ」
- withCheckedThrowingContinuation が continuation を生成し、async を一時停止させる
- callback の結果 → continuation.resume → async の戻り値として返る

