Loading...
Loading...
Compare original and translation side by side
axiom-icloud-drive-refaxiom-icloud-drive-ref// ✅ CORRECT: SwiftData with CloudKit sync
import SwiftData
@Model
class Task {
var title: String
var isCompleted: Bool
var dueDate: Date
init(title: String, isCompleted: Bool = false, dueDate: Date) {
self.title = title
self.isCompleted = isCompleted
self.dueDate = dueDate
}
}
// Configure CloudKit container
let container = try ModelContainer(
for: Task.self,
configurations: ModelConfiguration(
cloudKitDatabase: .private("iCloud.com.example.app")
)
)
// That's it! Sync happens automaticallyaxiom-swiftdata// ✅ 正确示例:带CloudKit同步的SwiftData实现
import SwiftData
@Model
class Task {
var title: String
var isCompleted: Bool
var dueDate: Date
init(title: String, isCompleted: Bool = false, dueDate: Date) {
self.title = title
self.isCompleted = isCompleted
self.dueDate = dueDate
}
}
// 配置CloudKit容器
let container = try ModelContainer(
for: Task.self,
configurations: ModelConfiguration(
cloudKitDatabase: .private("iCloud.com.example.app")
)
)
// 完成!同步会自动进行axiom-swiftdata// ✅ CORRECT: CKSyncEngine setup
import CloudKit
class SyncManager {
let syncEngine: CKSyncEngine
init() throws {
let config = CKSyncEngine.Configuration(
database: CKContainer.default().privateCloudDatabase,
stateSerialization: loadSyncState(),
delegate: self
)
syncEngine = try CKSyncEngine(config)
}
// Implement delegate methods
}
extension SyncManager: CKSyncEngineDelegate {
// Handle events
func handleEvent(_ event: CKSyncEngine.Event, syncEngine: CKSyncEngine) async {
switch event {
case .stateUpdate(let stateUpdate):
saveSyncState(stateUpdate.stateSerialization)
case .accountChange(let change):
handleAccountChange(change)
case .fetchedDatabaseChanges(let changes):
applyDatabaseChanges(changes)
case .fetchedRecordZoneChanges(let changes):
applyRecordChanges(changes)
case .sentRecordZoneChanges(let changes):
handleSentChanges(changes)
case .willFetchChanges, .didFetchChanges,
.willSendChanges, .didSendChanges:
// Optional lifecycle events
break
@unknown default:
break
}
}
// Next batch of changes to send
func nextRecordZoneChangeBatch(
_ context: CKSyncEngine.SendChangesContext,
syncEngine: CKSyncEngine
) async -> CKSyncEngine.RecordZoneChangeBatch? {
// Return pending local changes
let pendingChanges = getPendingLocalChanges()
return CKSyncEngine.RecordZoneChangeBatch(
pendingSaves: pendingChanges,
recordIDsToDelete: []
)
}
}// ✅ 正确示例:CKSyncEngine配置
import CloudKit
class SyncManager {
let syncEngine: CKSyncEngine
init() throws {
let config = CKSyncEngine.Configuration(
database: CKContainer.default().privateCloudDatabase,
stateSerialization: loadSyncState(),
delegate: self
)
syncEngine = try CKSyncEngine(config)
}
// 实现代理方法
}
extension SyncManager: CKSyncEngineDelegate {
// 处理事件
func handleEvent(_ event: CKSyncEngine.Event, syncEngine: CKSyncEngine) async {
switch event {
case .stateUpdate(let stateUpdate):
saveSyncState(stateUpdate.stateSerialization)
case .accountChange(let change):
handleAccountChange(change)
case .fetchedDatabaseChanges(let changes):
applyDatabaseChanges(changes)
case .fetchedRecordZoneChanges(let changes):
applyRecordChanges(changes)
case .sentRecordZoneChanges(let changes):
handleSentChanges(changes)
case .willFetchChanges, .didFetchChanges,
.willSendChanges, .didSendChanges:
// 可选生命周期事件
break
@unknown default:
break
}
}
// 下一批待发送的变更
func nextRecordZoneChangeBatch(
_ context: CKSyncEngine.SendChangesContext,
syncEngine: CKSyncEngine
) async -> CKSyncEngine.RecordZoneChangeBatch? {
// 返回待处理的本地变更
let pendingChanges = getPendingLocalChanges()
return CKSyncEngine.RecordZoneChangeBatch(
pendingSaves: pendingChanges,
recordIDsToDelete: []
)
}
}CKContainerCKDatabaseCKRecordCKRecordZoneCKAssetCKContainerCKDatabaseCKRecordCKRecordZoneCKAsset// ✅ Container and database
let container = CKContainer.default()
let privateDatabase = container.privateCloudDatabase
let publicDatabase = container.publicCloudDatabase
// ✅ Create record
let record = CKRecord(recordType: "Task")
record["title"] = "Buy groceries"
record["isCompleted"] = false
record["dueDate"] = Date()
// ✅ Save record
try await privateDatabase.save(record)
// ✅ Fetch record
let recordID = CKRecord.ID(recordName: "task-123")
let fetchedRecord = try await privateDatabase.record(for: recordID)
// ✅ Query records
let predicate = NSPredicate(format: "isCompleted == NO")
let query = CKQuery(recordType: "Task", predicate: predicate)
let (matchResults, _) = try await privateDatabase.records(matching: query)
for result in matchResults {
if case .success(let record) = result.1 {
print("Task: \(record["title"] as? String ?? "")")
}
}
// ✅ Delete record
try await privateDatabase.deleteRecord(withID: recordID)// ✅ 容器与数据库
let container = CKContainer.default()
let privateDatabase = container.privateCloudDatabase
let publicDatabase = container.publicCloudDatabase
// ✅ 创建记录
let record = CKRecord(recordType: "Task")
record["title"] = "Buy groceries"
record["isCompleted"] = false
record["dueDate"] = Date()
// ✅ 保存记录
try await privateDatabase.save(record)
// ✅ 获取记录
let recordID = CKRecord.ID(recordName: "task-123")
let fetchedRecord = try await privateDatabase.record(for: recordID)
// ✅ 查询记录
let predicate = NSPredicate(format: "isCompleted == NO")
let query = CKQuery(recordType: "Task", predicate: predicate)
let (matchResults, _) = try await privateDatabase.records(matching: query)
for result in matchResults {
if case .success(let record) = result.1 {
print("Task: \(record["title"] as? String ?? "")")
}
}
// ✅ 删除记录
try await privateDatabase.deleteRecord(withID: recordID)// ✅ Handle conflicts with savePolicy
let operation = CKModifyRecordsOperation(
recordsToSave: [record],
recordIDsToDelete: nil
)
// Save only if server version unchanged
operation.savePolicy = .ifServerRecordUnchanged
// OR: Always overwrite server
operation.savePolicy = .changedKeys // Only changed fields
operation.modifyRecordsResultBlock = { result in
switch result {
case .success:
print("Saved")
case .failure(let error as CKError):
if error.code == .serverRecordChanged {
// Conflict - merge manually
let serverRecord = error.serverRecord
let clientRecord = error.clientRecord
let merged = mergeRecords(server: serverRecord, client: clientRecord)
// Retry with merged record
}
}
}
privateDatabase.add(operation)// ✅ 使用savePolicy处理冲突
let operation = CKModifyRecordsOperation(
recordsToSave: [record],
recordIDsToDelete: nil
)
// 仅当服务器版本未变更时保存
operation.savePolicy = .ifServerRecordUnchanged
// 或者:始终覆盖服务器
operation.savePolicy = .changedKeys // 仅覆盖变更字段
operation.modifyRecordsResultBlock = { result in
switch result {
case .success:
print("Saved")
case .failure(let error as CKError):
if error.code == .serverRecordChanged {
// 冲突 - 手动合并
let serverRecord = error.serverRecord
let clientRecord = error.clientRecord
let merged = mergeRecords(server: serverRecord, client: clientRecord)
// 使用合并后的记录重试
}
}
}
privateDatabase.add(operation)| Scope | Accessibility | SwiftData Support | Use Case |
|---|---|---|---|
| Private | User only | ✅ Yes | Personal user data |
| Public | All users | ❌ No | Shared/public content |
| Shared | Invited users | ❌ No | Collaboration |
| 作用域 | 可访问性 | SwiftData支持 | 使用场景 |
|---|---|---|---|
| 私有 | 仅用户本人 | ✅ 支持 | 个人用户数据 |
| 公开 | 所有用户 | ❌ 不支持 | 共享/公开内容 |
| 共享 | 受邀用户 | ❌ 不支持 | 协作场景 |
// ✅ Private database (most common)
let privateDB = CKContainer.default().privateCloudDatabase
// User must be signed into iCloud
// Data syncs across user's devices
// Not visible to other users// ✅ 私有数据库(最常用)
let privateDB = CKContainer.default().privateCloudDatabase
// 用户必须登录iCloud
// 数据在用户的多设备间同步
// 对其他用户不可见// ✅ Public database (for shared content)
let publicDB = CKContainer.default().publicCloudDatabase
// Accessible to all app users
// Even unauthenticated users can read
// Writes require authentication
// Use for: Leaderboards, public content, discovery// ✅ 公开数据库(用于共享内容)
let publicDB = CKContainer.default().publicCloudDatabase
// 所有应用用户均可访问
// 未认证用户也可读取
// 写入需要认证
// 适用场景:排行榜、公开内容、发现页// ✅ Shared database (collaboration)
let sharedDB = CKContainer.default().sharedCloudDatabase
// For CKShare-based collaboration
// Users invited to specific record zones
// Use for: Shared documents, team data// ✅ 共享数据库(协作场景)
let sharedDB = CKContainer.default().sharedCloudDatabase
// 基于CKShare的协作场景
// 用户可被邀请至特定记录区域
// 适用场景:共享文档、团队数据// ✅ Store files as CKAsset
let imageURL = saveImageToTempFile(image) // Must be file URL
let asset = CKAsset(fileURL: imageURL)
let record = CKRecord(recordType: "Photo")
record["image"] = asset
record["caption"] = "Sunset"
try await privateDatabase.save(record)
// ✅ Retrieve asset
let fetchedRecord = try await privateDatabase.record(for: recordID)
if let asset = fetchedRecord["image"] as? CKAsset,
let fileURL = asset.fileURL {
let imageData = try Data(contentsOf: fileURL)
let image = UIImage(data: imageData)
}// ✅ 将文件存储为CKAsset
let imageURL = saveImageToTempFile(image) // 必须是文件URL
let asset = CKAsset(fileURL: imageURL)
let record = CKRecord(recordType: "Photo")
record["image"] = asset
record["caption"] = "Sunset"
try await privateDatabase.save(record)
// ✅ 获取资源
let fetchedRecord = try await privateDatabase.record(for: recordID)
if let asset = fetchedRecord["image"] as? CKAsset,
let fileURL = asset.fileURL {
let imageData = try Data(contentsOf: fileURL)
let image = UIImage(data: imageData)
}// ✅ Fetch all records on first launch
func performInitialSync() async throws {
let predicate = NSPredicate(value: true) // All records
let query = CKQuery(recordType: "Task", predicate: predicate)
let (results, _) = try await privateDatabase.records(matching: query)
for result in results {
if case .success(let record) = result.1 {
saveToLocalDatabase(record)
}
}
}// ✅ 首次启动时获取所有记录
func performInitialSync() async throws {
let predicate = NSPredicate(value: true) // 所有记录
let query = CKQuery(recordType: "Task", predicate: predicate)
let (results, _) = try await privateDatabase.records(matching: query)
for result in results {
if case .success(let record) = result.1 {
saveToLocalDatabase(record)
}
}
}// ✅ Use CKServerChangeToken for incremental fetches
func fetchChanges(since token: CKServerChangeToken?) async throws {
let zoneID = CKRecordZone.ID(zoneName: "Tasks")
let config = CKFetchRecordZoneChangesOperation.ZoneConfiguration(
previousServerChangeToken: token
)
let operation = CKFetchRecordZoneChangesOperation(
recordZoneIDs: [zoneID],
configurationsByRecordZoneID: [zoneID: config]
)
operation.recordWasChangedBlock = { recordID, result in
if case .success(let record) = result {
updateLocalDatabase(with: record)
}
}
operation.recordWithIDWasDeletedBlock = { recordID, _ in
deleteFromLocalDatabase(recordID)
}
operation.recordZoneFetchResultBlock = { zoneID, result in
if case .success(let (token, _, _)) = result {
saveChangeToken(token) // For next fetch
}
}
try await privateDatabase.add(operation)
}// ✅ 使用CKServerChangeToken实现增量获取
func fetchChanges(since token: CKServerChangeToken?) async throws {
let zoneID = CKRecordZone.ID(zoneName: "Tasks")
let config = CKFetchRecordZoneChangesOperation.ZoneConfiguration(
previousServerChangeToken: token
)
let operation = CKFetchRecordZoneChangesOperation(
recordZoneIDs: [zoneID],
configurationsByRecordZoneID: [zoneID: config]
)
operation.recordWasChangedBlock = { recordID, result in
if case .success(let record) = result {
updateLocalDatabase(with: record)
}
}
operation.recordWithIDWasDeletedBlock = { recordID, _ in
deleteFromLocalDatabase(recordID)
}
operation.recordZoneFetchResultBlock = { zoneID, result in
if case .success(let (token, _, _)) = result {
saveChangeToken(token) // 用于下次获取
}
}
try await privateDatabase.add(operation)
}<!-- iCloud capability -->
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudKit</string>
</array>
<!-- CloudKit container -->
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.com.example.app</string>
</array><!-- iCloud功能权限 -->
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudKit</string>
</array>
<!-- CloudKit容器 -->
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.com.example.app</string>
</array>| Task | Modern API (iOS 17+) | Legacy API |
|---|---|---|
| Structured data sync | SwiftData + CloudKit | CKSyncEngine or CKDatabase |
| Custom persistence sync | CKSyncEngine | CKDatabase |
| Conflict resolution | Automatic (SwiftData/CKSyncEngine) | Manual (savePolicy) |
| Account changes | Handled automatically | Manual detection |
| Monitoring | CloudKit Console telemetry | Manual logging |
| 任务 | 现代API(iOS 17+) | 遗留API |
|---|---|---|
| 结构化数据同步 | SwiftData + CloudKit | CKSyncEngine或CKDatabase |
| 自定义持久化同步 | CKSyncEngine | CKDatabase |
| 冲突解决 | 自动处理(SwiftData/CKSyncEngine) | 手动处理(savePolicy) |
| 账户变更 | 自动处理 | 手动检测 |
| 监控 | CloudKit控制台遥测 | 手动日志 |
axiom-swiftdataaxiom-storageaxiom-icloud-drive-refaxiom-cloud-sync-diagaxiom-swiftdataaxiom-storageaxiom-icloud-drive-refaxiom-cloud-sync-diag