SwiftDataとCloudKitの連携メモ

SwiftDataとCloudKitの連携について実際に試してみたのでメモ。


やりたいこと

SwiftDataで保存したデータをiCloud上に保存し、他の端末と同期させる。

環境

  • Xcode 26.0.1

  • Swift 5

  • iOS 26

  • macOS Tahoe 26.0.1

新規プロジェクト作成

StorageでSwiftDataを選択し、Host in CloudKitにチェックを入れる。

Host in CloudKitにチェックを入れた時の差分は下記の通り。

  • Signing & CapabilitiesにBackground ModesとiCloudが追加されている

  • Background ModesではRemote Notificationsにチェックが入っている

  • iCloudではCloudKitにチェックが入っている

Host in CloudKitのチェックを入れてない状態のプロジェクトの場合は上記の変更を加えればOK。

Signing & Capabilitiesの設定

Sigining & CapabilitiesのiCloudのセクションにあるContainersで+ボタンをクリックし、新たにiCloud Containerを作成する。

iCloud ContainerのIdentifierはドキュメントを見た感じ先頭に「iCloud.」を付けていたのでそれに則って命名して作成。
今回は「iCloud.[Bundle ID]」の形で命名した。

この状態でビルドするとコンソールにエラーが流れる。

Unresolved error loading container Error Domain=NSCocoaErrorDomain Code=134060 "A Core Data error occurred." UserInfo={NSLocalizedFailureReason=CloudKit integration requires that all attributes be optional, or have a default value set. The following attributes are marked non-optional but do not have a default value:
Item: timestamp}

CloudKitと連携する場合、Modelのパラメーターはoptionalかデフォルト値の設定が必要とのこと。

Itemのtimestampにデフォルト値を設定する。

// Item.swift

import Foundation
import SwiftData

@Model
final class Item {
    var timestamp: Date = Date()
    
    init(timestamp: Date) {
        self.timestamp = timestamp
    }
}

修正後、改めてビルドすると無事アプリが立ち上がった。

シミュレーター上の設定アプリからApple Accountにログインした状態で試しにタイムスタンプをいくつか追加してみる。

その後、同じApple Accountでログインしている実機端末でアプリをビルドして確認したところ、データの同期ができているのが確認できた。

CloudKitとの同期を切りたい場合

modelConfigurationのcloudKitDatabaseを.noneにすると端末に保存されているデータはそのまま、CloudKitとの同期を切ることができる。

let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false, cloudKitDatabase: .none)

CloudKit ConsoleでiCloudに保存されたデータを確認する

CloudKit ConsoleはSigning & CapabilitilesのiCloudセクションにあるCloudKit Consoleから開くことができる。

開いたら左上のCloudKit Databaseを選択。

ページの左上から今回作成したiCloud Containerを選択し、左のカラムのDataセクションからRecordsを選択。

各項目は下記のように設定。

  • DB: Private Database

  • Zone: com.apple.coredata.cloudkit.zone

  • Query Records

  • RECORD TYPE: CD_Item

  • FIELDS: All

設定できたらQuery Recordsボタンをクリック。

すると「Field 'recordName' is not marked queryable」というエラーが発生。

IndexesにrecordNameというフィールドがqueryableとして登録されていないのが原因なので追加する。

左のカラムのSchemaセクションからIndexesを選択。

Indexesのタイトル横の+ボタンをクリックしAdd Index画面を開いて下記のように入力。

  • Record Type: CD_Item

  • Name: recordName

  • Type: QUERYABLE

  • Field: recordName

AddボタンをクリックするとIndexesのCD_Item配下にrecordNameが追加される。

Fieldsが___recordIDになっているがこれで合っている。

これでRecordsに戻って先ほどと同じクエリを実行するとiCloudに保存されているItemが表示される。

その他メモと気になったこと(追々調べる)

  • Modelの制約は他にもあるようで、気を付ける必要がある

    • ドキュメントには@Attribute、@Relationshipについての記載がある

  • リリースする際は別途CloudKit Consoleでデプロイ作業が必要

  • 保存したデータがある状態でModelのパラメータを変更した場合どうなる?

  • CloudKit Consoleで保存したデータを確認する際、今回Development環境だから自分が保存したレコードだけ表示されたが、本番環境だとどうなる?

参考記事

いいなと思ったら応援しよう!