SwiftUI × CloudKit における「withCheckedThrowingContinuation」について…

朝の実(Asanomi)アイコン アプリ開発

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 の戻り値として返る
sho shimizu

朝専用SNS「朝の実(Asanomi)」を個人開発しています。
本業や育児の合間に、SwiftUIで少しずつ作っているアプリです。

朝の時間が好きな人に向けた、小さなSNSを育てています。
開発記録や日々の学びをまとめています。

sho shimizuをフォローする
アプリ開発技術解説朝の実
シェアする
sho shimizuをフォローする