如何提前向用户展示NSPersistentCloudKitContainer的iCloud同步状态?
解决iCloud同步进度提前显示的问题
你的代码问题在于只监听了CloudKit事件的类型,却忽略了事件的状态变化——eventChangedNotification在事件开始和结束时都会触发,但你之前只根据类型设置isSyncing,还加了固定2秒的强制关闭,这就导致进度条只能在事件快结束时才显示。
要更早通知用户同步开始,需要从这几个方面调整:
- 跟踪事件的
state(开始/结束/失败),事件启动时立刻标记同步中 - 处理多个同步事件同时进行的情况,避免单个事件结束就提前关闭进度条
- 监听首次同步的初始化阶段,覆盖启动时的云数据下载场景
修改后的CloudSyncManager代码
import Combine import CoreData import SwiftUI class CloudSyncManager: ObservableObject { @Published var isSyncing: Bool = false // 用Set存储正在进行的同步事件ID,避免多事件冲突 private var activeSyncEvents: Set<UUID> = [] private var cancellables: Set<AnyCancellable> = [] init(persistentContainer: NSPersistentCloudKitContainer) { // 监听CloudKit事件状态变化 NotificationCenter.default.publisher(for: NSPersistentCloudKitContainer.eventChangedNotification) .sink { [weak self] notification in guard let self, let event = notification.userInfo?[NSPersistentCloudKitContainer.eventNotificationUserInfoKey] as? NSPersistentCloudKitContainer.Event else { return } DispatchQueue.main.async { switch event.state { case .started: // 只关注导入、导出、初始化类型的同步事件 if [.import, .export, .setup].contains(event.type) { self.activeSyncEvents.insert(event.id) self.isSyncing = !self.activeSyncEvents.isEmpty } case .ended, .failed: self.activeSyncEvents.remove(event.id) self.isSyncing = !self.activeSyncEvents.isEmpty default: break } } } .store(in: &cancellables) // 监听首次iCloud同步完成(针对启动时的初始数据下载) persistentContainer.initialCloudKitSyncCompletionHandler = { [weak self] error in DispatchQueue.main.async { // 如果没有活跃事件了,就关闭同步状态 if self?.activeSyncEvents.isEmpty ?? true { self?.isSyncing = false } } } // 初始化时检查是否有正在进行的同步事件 checkInitialSyncState(persistentContainer: persistentContainer) } private func checkInitialSyncState(persistentContainer: NSPersistentCloudKitContainer) { persistentContainer.fetchAllEvents { [weak self] events, error in guard let self, let events = events else { return } DispatchQueue.main.async { // 筛选出正在进行的同步事件 let ongoingEvents = events.filter { [.import, .export, .setup].contains($0.type) && $0.state == .started } self.activeSyncEvents = Set(ongoingEvents.map { $0.id }) self.isSyncing = !self.activeSyncEvents.isEmpty } } } }
使用说明
在初始化Core Data容器时,把容器传给CloudSyncManager:
// 你的Core Data配置代码 let persistentContainer = NSPersistentCloudKitContainer(name: "你的模型名称") let cloudSyncManager = CloudSyncManager(persistentContainer: persistentContainer) // SwiftUI视图中使用 struct ContentView: View { @StateObject private var syncManager = cloudSyncManager var body: some View { if syncManager.isSyncing { ProgressView("正在同步iCloud数据...") .progressViewStyle(CircularProgressViewStyle()) .frame(maxWidth: .infinity, maxHeight: .infinity) } else { // 显示你的主界面 HomeView() } } }
关键改进点
- 跟踪活跃事件:用
Set<UUID>记录正在进行的同步事件ID,只有所有事件都结束,才会把isSyncing设为false - 监听事件状态:当事件
state为.started时立刻开启进度条,.ended或.failed时移除对应事件 - 覆盖首次同步:通过
initialCloudKitSyncCompletionHandler处理启动阶段的初始数据下载,避免漏掉这部分同步状态 - 初始状态检查:初始化时主动查询当前正在进行的事件,防止刚启动就错过已经开始的同步
内容的提问来源于stack exchange,提问作者Petr Smejkal
相关产品推荐
相关产品推荐

