问题描述:
环境:
- Xcode 版本: 16.3
- *macOS 版本: 15.4
- 项目类型: SwiftUI App with SwiftData
问题摘要:
当在 Xcode 项目的 "Signing & Capabilities" 中为启用了 iCloud 能力的应用关联一个具体的 iCloud Container 时,即使代码中并未显式启用 CloudKit 同步(例如,未在 ModelConfiguration
中设置 cloudKitDatabase
),SwiftData 的 ModelContainer
在应用启动初始化时也会立即失败并导致崩溃。如果仅启用 iCloud 能力但不选择任何 Container,应用可以正常启动。此问题在使用空的 Schema([])
进行测试时依然稳定复现。
复现步骤 (使用最小复现项目 - MRE):
-
使用 Xcode 16.3 创建一个新的 SwiftUI App 项目 (例如,命名为
CloudKitCrashTest
)。 -
在创建时不要勾选 "Host in CloudKit",或者,如果勾选了,先确保后续步骤覆盖相关设置。Storage 选择
None
或SwiftData
均可复现。 -
修改
CloudKitCrashTestApp.swift
文件,添加 SwiftData 导入和基本的ModelContainer
初始化逻辑。关键代码如下:import SwiftUI import SwiftData @main struct CloudKitCrashTestApp: App { let sharedModelContainer: ModelContainer init() { // 使用空 Schema 进行诊断 let schema = Schema([]) // *不* 指定 cloudKitDatabase let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { sharedModelContainer = try ModelContainer(for: schema, configurations: [modelConfiguration]) print("ModelContainer created successfully.") } catch { // 在关联 Container 后,会在此处崩溃 fatalError("Could not create ModelContainer: \(error)") } } var body: some Scene { WindowGroup { ContentView() .modelContainer(sharedModelContainer) } } } // ... ContentView 定义 ... -
进入项目的
Signing & Capabilities
标签页。 -
点击
+ Capability
添加iCloud
。 -
在
iCloud
服务中,勾选CloudKit
。 -
此时,不要在
Containers
部分选择任何容器。 -
运行应用: 应用应该能够成功启动,并在控制台打印 "ModelContainer created successfully."。
-
停止应用。
-
回到
Signing & Capabilities
->iCloud
->Containers
。 -
点击
+
添加一个新的自定义容器,或选择 Xcode 默认建议的容器。确保一个容器 ID 被明确选中。 -
再次运行应用: 应用现在会在启动时立即崩溃,
fatalError
被触发。
预期结果:
即使在 Signing & Capabilities
中关联了 iCloud Container,应用也应该能够成功初始化 ModelContainer
(尤其是当代码中未使用 cloudKitDatabase
或使用空 Schema 时),不应崩溃。
实际结果:
应用在 ModelContainer
初始化时崩溃,抛出 fatalError
,错误信息为:
Could not create ModelContainer: SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer, _explanation: nil)
补充说明:
- 此问题在 iPhone 模拟器上稳定复现。
- 尝试清理构建文件夹 (Clean Build Folder)、删除派生数据 (Derived Data) 未能解决问题。
- 使用 Xcode 模板创建项目(勾选 "Host in CloudKit")并在之后手动取消选择 Container 可以运行,但一旦重新选择 Container 就会崩溃,现象一致。
- 这表明问题与
ModelContainer
初始化过程在检测到项目关联了具体 iCloud Container 标识符(可能涉及读取.entitlements
文件或准备相关环境)时发生的内部错误有关,而不是由于实际的 CloudKit 同步代码或模型定义。
影响: 此 Bug 阻止了在当前的 Xcode 和 macOS 环境下开发和测试任何需要关联 iCloud Container 的 SwiftData 应用。
When you create a ModelConfiguration, the default value of the cloudKitDatabase attribute .automatic
, which tells SwiftData to enable CloudKit synchronization using the primary CloudKit container from the app’s entitlements. That is why you see that SwiftData automatically picks up the CloudKit container, if you configure one in your project, and enables CloudKit integration.
If you don't like the default behavior, pass .none when you create the model configuration.
Assuming that you use the Xcode template code to trigger the crash, most likely, you will see the following message in your Xcode console:
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}
The log makes clear that the failure is triggered because Item: timestamp
was non-optional
and doesn't have a default value. You can fix the crash by adding a default value, as shown below:
@Model final class Item { var timestamp: Date = Date.now // Adding a default vaule here. init(timestamp: Date) { self.timestamp = timestamp } }
If this is not your case, you can look into your Xcode console log to see if there is any other error message indicating why the app fails to create the model container.
Best,
——
Ziqiao Chen
Worldwide Developer Relations.