SwiftData数据同步iCloud需要先配置iCloud容器。
配置iCloud容器
1、打开 Xcode 项目设置
在 Xcode 的项目导航中,点击项目的根目录,然后选择目标 (target) 设置。
2、进入 Signing & Capabilities
在项目设置中,点击 Signing & Capabilities 选项卡。
3、添加 iCloud 能力
点击左上方的 + Capability 按钮,搜索并选择 iCloud。这会自动为项目添加 iCloud 支持。
双击列表中的iCloud选项,将iCloud添加到项目中。
4、配置 iCloud 容器
选择添加的 iCloud 项目后,你会看到多个选项。确保勾选 CloudKit。
如果你的应用需要使用特定的容器,可以点击 Edit 按钮并选择或添加新的 iCloud 容器。
如果勾选CloudKit后,iCloud如果没有设置默认容器,则需要手动添加容器。
提示内容为:如果命名的容器不存在,Xcode 将创建一个新的容器,将其添加到 App ID,然后将新容器添加到应用程序的权利中。
这里应该使用带有“iCloud”的应用程序包 ID 前缀,例如:
iCloud.com.fangjunyu.hackingwithswift
点击“OK”按钮并创建对应的CloudKit容器。
刚开始Containers容器可能是红色,可以点击下面的刷新按钮同步,同步后颜色变为黑色。
5、新增Remote Notifications功能
再次点击Capability功能:
找到并添加Background Modes功能:
在Background Modes中勾选Remote notifications功能。
勾选该功能后,当iCloud中的数据发送变化时,应用程序就会收到通知,就可以实现本地同步。
不勾选该功能,Xcode可能会输出类似的提示:
BUG IN CLIENT OF CLOUDKIT: CloudKit push notifications require the 'remote-notification' background mode in your info plist.
告知要求CloudKit 推送通知需要信息列表中的“远程通知”后台模式。
iCloud三种不同的数据存储方式
在 iCloud 中,Key-value storage、iCloud Documents 和 CloudKit 是三种不同的数据存储方式,分别适用于不同的应用场景:
1、Key-value storage
用途:适用于保存小量、简单的用户数据,例如设置、偏好和轻量级的应用状态。
特点:
提供一个键-值对(key-value pairs)的存储模型,类似于 NSUserDefaults。
数据可以在多个设备之间同步。
由于存储量小且同步速度快,适合于用户设置和状态信息(如主题、音量设置等)的跨设备同步。
示例:在 iPhone 上保存的用户设置可以通过 iCloud 同步到 iPad。
2、iCloud Documents
用途:专门用于存储用户文件和文档,例如文本文件、图片、视频等。
特点:
为用户的文件提供集中存储,并能在所有设备上访问。
支持应用数据的跨设备无缝同步,但用户可以直接访问这些文件,因此适合用户文件管理的需求。
Apple 提供了 UIDocument 类来帮助管理文件,处理文件的读写和保存过程。
示例:iCloud Drive 上的文档,如 Pages、Numbers 或用户上传的 PDF 文件等。
3、CloudKit
用途:提供一个云端数据库服务,适用于保存更复杂的结构化数据,如应用的核心数据、关系型数据等。
特点:
支持公有和私有数据库,可以存储大规模数据。
适合复杂数据结构,如包含关系的用户数据、共享内容、或应用的核心数据存储。
开发者可以利用 CloudKit 的 API 创建、读取、更新和删除记录。支持用户间数据共享,且具备权限控制。
示例:社交类应用的用户动态信息、跨设备的内容共享(例如笔记和提醒)、游戏的多人数据等。
使用场景对比:
Key-value storage 适合轻量级配置和偏好设置。
iCloud Documents 用于文件存储和管理,适合用户生成的内容。
CloudKit 则适合需要数据库功能的应用,能存储结构化和关联性数据,支持数据同步和复杂的应用逻辑。
查看CloudKit容器
在 Apple Developer 网站上可以查看创建的 CloudKit 容器,但这需要在 Xcode 中成功创建容器并同步后,才会出现在 Apple Developer 网站的容器列表中。
1、打开 Apple Developer 网站
访问 Apple Developer 网站 并登录开发者账户。
2、导航到 CloudKit 容器管理页面
点击顶部菜单中的账户。
在页面中,选择服务-CloudKit(英文)。
3、查看容器列表
在 CloudKit 控制台页面,点击CloudKit数据库。
这里的页面是英文,使用的是谷歌页面翻译,实际的名称为CloudKit Database。
容器名称(如 iCloud.com.fangjunyu.hackingwithswift)应该出现在列表中。
如果未看到容器,请确保在 Xcode 中正确添加了 iCloud 功能并指定了容器。
CloudKit要求
配置CloudKit容器后,需要了解CloudKit对模型有严格要求:
1、所有的属性必须有 默认值 或 可选类型。
2、所有关系也必须是 可选的。
检查创建的模型。如果之前的修复未完全满足这些要求(如遗漏了某些字段的默认值或未声明为可选类型),仍会导致 ModelContainer 初始化失败。
初始化失败截图:
会提示下面类似的报错:
Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: SwiftData.SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer)
参考模型
下面是提供默认值的属性,都需要添加默认值,如果是关系则需要为可选类型:
@Model
class User {
var name: String = "Anonymous"
var city: String = "Unknown"
var joinDate: Date = Date.now
@Relationship(deleteRule: .cascade) var jobs: [Job]? = [Job]()
init(name: String, city: String, joinDate: Date, jobs: [Job]? = nil) {
self.name = name
self.city = city
self.joinDate = joinDate
self.jobs = jobs
}
}
我在添加默认值和可选类型过程中,因为忘记给关系添加可选类型报错,一时间还找到问题根源,因此需要注意类似的问题:
[Job]? = [Job]()
以上所有的配置完成之后,SwiftData就可以正确的同步到iCloud。
本地数据同步问题
在勾选 CloudKit 后,UserDefaults 和 URL 指向的 Documents 目录中的数据不会自动同步到 iCloud。CloudKit 和 iCloud 并不自动同步本地数据,需要特定的 API 或设置。以下是它们的存储行为与 iCloud 的关系:
1、UserDefaults
本地存储:默认情况下,UserDefaults 只在本地设备上存储数据,不会自动与 iCloud 同步。
iCloud Key-Value Storage:如果希望在 iCloud 中同步 UserDefaults 的部分数据,可以通过 NSUbiquitousKeyValueStore,它提供了键值存储(key-value storage)与 iCloud 的同步。这个功能适合简单的偏好设置和小数据量的同步。
使用 iCloud Key-Value Storage 时,需要在 Xcode 中为项目勾选 iCloud 的 Key-value storage 功能,否则数据不会同步到 iCloud。
如何使用:
let iCloudStore = NSUbiquitousKeyValueStore.default
// 保存数据
iCloudStore.set("John Doe", forKey: "username")
// 读取数据
let username = iCloudStore.string(forKey: "username")
iCloudStore.synchronize()
需要注意,这种同步仅限于轻量级数据,数据量大的内容需要其他解决方案,比如 CloudKit。
2、Documents 目录中的文件(URL Documents Storage)
本地存储:通常存储在 Documents 或 Library 中的文件,默认也不会自动同步到 iCloud。
iCloud Drive 手动存储:如果你希望将某些文件同步到 iCloud,开发者需要主动将文件存储到 iCloud Drive 目录下(例如在 Documents 目录中创建一个 iCloud 目录并将文件写入)。
FileManager 的 url(forUbiquityContainerIdentifier:) 方法用于访问 iCloud Documents 功能的存储路径。将文件写入这个路径可以实现文件的 iCloud 同步,但这需要在 Xcode 中启用 iCloud Documents 功能。
使用方式:
let iCloudURL = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents").appendingPathComponent("yourFileName")
// 将文件写入到 iCloudURL 指定的位置
总结
以上是SwiftData数据同步到iCloud的全部知识,主要涉及的知识点为:
- Xcode项目配置;
- iCloud三种数据存储方式的介绍
- 从网页中查看CloudKit容器
- CloudKit对模型的要求
- 以及本地数据同步的问题
实际上,我并没有测试UserDefaults和Documents本地文件同步iCloud的步骤,可能需要等待后面开发具体应用时,涉及到这方面知识点,再进一步完善本文。
需要注意的是,SwiftData同步iCloud后,会出现很多迷之错误,没有具体的报错描述,只会给你一个报错。例如你的模型没有按照CloudKit要求,有一个字段没有赋值或者关系没有设置可选类型,运行Xcode时就会有报错,而且不会给你提醒,必须要自己找。
所以,一切都要自己努力,学习和了解Apple新推出的这一存储功能。
补充知识
NSUbiquitousKeyValueStore是什么?
NSUbiquitousKeyValueStore 是 Apple 提供的 iCloud 功能,用于在轻量级应用数据(如用户偏好设置、配置或状态)在启用 iCloud 的 Apple 设备之间进行同步。它不是 SwiftUI 的特有功能,而是 Foundation 框架的一部分,可以在 Swift 和 Objective-C 中使用。
什么是 NSUbiquitousKeyValueStore?
iCloud 的轻量级键值存储:主要用于存储小型数据,例如用户设置、应用配置等。每个应用的总存储空间有限(当前约 1 MB),适合频繁更新但体量小的数据。
跨设备同步:存储的数据会自动通过 iCloud 同步到用户的其他 Apple 设备。只要用户在设备上登录同一个 Apple ID 并开启 iCloud,数据就会保持一致。
NSUbiquitousKeyValueStore 的工作方式
本地与 iCloud 数据的同步:数据存入 NSUbiquitousKeyValueStore 后,会自动同步到 iCloud,在其他设备上也能读取和使用。
手动同步:可以通过 synchronize() 方法手动触发数据同步,确保最新数据上传到 iCloud 或从 iCloud 下载更新。
基本用法
在 Swift 中使用时,我们首先要访问默认的 NSUbiquitousKeyValueStore 实例,然后存储或读取数据:
let iCloudStore = NSUbiquitousKeyValueStore.default
// 保存数据
iCloudStore.set("John Doe", forKey: "username")
// 读取数据
let username = iCloudStore.string(forKey: "username")