Skip to main content

Core Data の iCloud 対応

設定関連

プロジェクト作成時に設定する場合

  • Storage: SwiftData
  • Host in CloudKit : On

あとから iCloud 対応にする場合

  • Signing and Capability
    • iCloud 追加
      • CloudKit にチェック
      • Container 追加してチェック。例: com.sugoideveloper.SugoiApp
        • アプリと同じ識別子が推奨されるようだが、同じでなくても動作はする
    • Background Modes 追加
      • Background fetch?

各ファイルでの実装

@main - XxxApp

  • iCloud でない版と一緒

テンプレ

swift
import SwiftUI
import SwiftData

@main
struct SugoiApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([
Book.self, // ← ★ ここを自前のモデルに置き換える、追加する
])
let modelConfiguration = ModelConfiguration(
schema: schema,
isStoredInMemoryOnly: false
)

do {
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()

var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(sharedModelContainer)
}
}
識別子を明示的に指定する場合

entitlements の iCloud Container Identifier に設定されていれば問題なさそうであるが、
明示必要なケースもあるそうなので、いったんメモ

swift
let modelConfiguration = ModelConfiguration(
schema: schema,
cloudKitDatabase: .private("iCloud.com.example.SugoiApp")
)

モデル

  • どこでも良いが、自分ルールとして PersistentModel フォルダに置くことにした

注意点

iCloud なし版の SwiftData と比べての制約

  • iCloud 対応時は unique 制約付与が不可
  • プロパティはすべて optional ( = String? 等 ) であること
  • プロパティは定義時かコンストラクタで初期値がセットしてあること

そうでないと同期されないし、アプリ実行時のログによく見ると、その旨の警告が出る

テンプレ

swift
import SwiftUI
import SwiftData

@Model
class Book: Identifiable {
var id: UUID = UUID()

var name : String? = ""
var order : Int? = 0

init(
name : String
) {
self.name = name
}
}

ContentView

テンプレ

例は NavigationSplitView を使うとして..

swift
import SwiftUI

struct ContentView: View {
var body: some View {
NavigationSplitView {
BookListView()
} content: {
Text("Directory")
} detail: {
Text("Contents")
}
}
}

一覧の取得

swift
import SwiftUI
import SwiftData

struct BookListView: View {
@Environment(\.modelContext) private var modelContext

@Query private var books: [Book]

@State var selection: Book? = nil

var body: some View {
List(books, id: \.self, selection: $selection) { book in
HStack {
Image(systemName: "square.fill")
//.foregroundStyle(Color(cgColor: calendar.cgColor))
Text(book.name ?? "-")
}
}
}
}