Core data NSPersistentCloudKitContainer:如何检查数据是否同步到CloudKit
我已经实现了Core data NSPersistentCloudKitContainer:如何检查数据是否同步到CloudKit,core-data,cloudkit,ios13,nspersistentcloudkitcontainer,Core Data,Cloudkit,Ios13,Nspersistentcloudkitcontainer,我已经实现了NSPersistentCloudKitContainer以将我的数据同步到CloudKit,我想知道同步已经完成,没有其他待同步的更改 当我尝试重新安装应用程序时,我开始从CloudKit获取数据,它开始在控制台中打印某些日志。 从CloudKit获取所有数据大约需要30秒。一些日志提到了nscloudkitmrroringdelegate。看起来nscloudkitmrroringdelegate知道剩余的同步请求,但我找不到任何有关确保同步完成的信息 这里有几个日志显示NSCl
NSPersistentCloudKitContainer
以将我的数据同步到CloudKit
,我想知道同步已经完成,没有其他待同步的更改
当我尝试重新安装应用程序时,我开始从CloudKit获取数据,它开始在控制台中打印某些日志。
从CloudKit获取所有数据大约需要30秒。一些日志提到了nscloudkitmrroringdelegate
。看起来nscloudkitmrroringdelegate
知道剩余的同步请求,但我找不到任何有关确保同步完成的信息
这里有几个日志显示NSCloudKitMirroringDelegate知道同步何时完成
CoreData:CloudKit:CoreData+CloudKit:-NSCloudKitMirroringDelegate
checkAndExecuteNextRequest::检查挂起的请求。
CoreData:CloudKit:CoreData+CloudKit:-[NSCloudKitMirroringDelegate
_排队请求:][u block_invoke(714):排队请求:A2BB21B3-BD1B-4500-865C-6C848D67081D
CoreData:CloudKit:CoreData+CloudKit:-[NSCloudKitMirroringDelegate
checkAndExecuteNextRequest]\u block\u invoke(2085):
:推迟额外的工作。
仍有一个活动请求:A3E1D4A4-2BDE-4E6A-8DB4-54C96BA0579E
CoreData:CloudKit:CoreData+CloudKit:-[NSCloudKitMirroringDelegate
checkAndExecuteNextRequest]_block_invoke(2092):
:没有更多的请求发送到
执行。
有没有办法知道数据已完全同步?我需要向用户展示特定的UI。引用苹果开发者论坛上类似问题中的“框架工程师”的话:“这是一个谬误”。在分布式系统中,您无法真正知道“同步是否完成”,因为另一个设备(此时可能在线或离线)可能有未同步的更改 也就是说,这里有一些技术可以用来实现用例,这些用例往往会激发人们了解同步状态的欲望 添加默认/示例数据 给他们一个按钮来添加特定的默认/示例数据,而不是自动将其添加到应用程序中。这两种方法在分布式环境中都能更好地工作,并使应用程序的功能和示例数据之间的区别更加清晰 例如,在我的一个应用程序中,用户可以创建一个“上下文”列表(例如“家庭”、“工作”),在其中可以添加要执行的操作。如果用户是第一次使用该应用程序,“上下文”列表将为空。这很好,因为他们可以添加上下文,但最好提供一些默认值 我没有检测首次启动并添加默认上下文,而是添加了一个仅在数据库中没有上下文时才显示的按钮。也就是说,如果用户导航到“下一个操作”屏幕,并且没有上下文(即
contexts.isEmpty
),则该屏幕还包含“添加默认GTD上下文”按钮。一旦添加了上下文(由用户或通过同步),按钮就会消失
以下是屏幕的快捷界面代码:
import SwiftUI
/// The user's list of contexts, plus an add button
struct NextActionsLists: View {
/// The Core Data enviroment in which we should perform operations
@Environment(\.managedObjectContext) var managedObjectContext
/// The available list of GTD contexts to which an action can be assigned, sorted alphabetically
@FetchRequest(sortDescriptors: [
NSSortDescriptor(key: "name", ascending: true)]) var contexts: FetchedResults<ContextMO>
var body: some View {
Group {
// User-created lists
ForEach(contexts) { context in
NavigationLink(
destination: ContextListActionListView(context: context),
label: { ContextListCellView(context: context) }
).isDetailLink(false)
.accessibility(identifier: "\(context.name)") // So we can find it without the count
}
.onDelete(perform: delete)
ContextAddButtonView(displayComplicationWarning: contexts.count > 8)
if contexts.isEmpty {
Button("Add Default GTD Contexts") {
self.addDefaultContexts()
}.foregroundColor(.accentColor)
.accessibility(identifier: "addDefaultContexts")
}
}
}
/// Deletes the contexts at the specified index locations in `contexts`.
func delete(at offsets: IndexSet) {
for index in offsets {
let context = contexts[index]
context.delete()
}
DataManager.shared.saveAndSync()
}
/// Adds the contexts from "Getting Things Done"
func addDefaultContexts() {
for name in ["Calls", "At Computer", "Errands", "At Office", "At Home", "Anywhere", "Agendas", "Read/Review"] {
let context = ContextMO(context: managedObjectContext)
context.name = name
}
DataManager.shared.saveAndSync()
}
}
如果用户同时在两台设备上修改“内容”,其中一台将覆盖另一台
相反,让内容成为“贡献”:
然后,你的应用程序将读取贡献,并使用适合你的应用程序的策略将它们合并。最简单/最懒惰的方法是使用修改后的日期并选择最后一个日期
对于我上面提到的应用程序,我选择了两种策略:
- 对于简单字段,我只是将它们包含在实体中。最后一位作家获胜
- 对于注释(即大字符串-大量数据将丢失),我创建了一个关系(每个项目有多个注释),并允许用户向一个项目添加多个注释(自动为用户添加时间戳)。这既解决了数据模型问题,又为用户添加了类似于Jira注释的特性。现在,用户可以编辑现有的便笺,在这种情况下,最后一个写更改的设备将“获胜”
- 在UserDefaults中存储首次运行标志。如果没有该标志,则显示首次跑步屏幕。这种方法使您的第一次运行成为每设备的事情。也给用户一个“跳过”按钮。(示例代码来自)
- 在一个表上设置FetchRequestController,如果用户以前使用过你的应用程序,该表中肯定会有数据。如果获取的结果为空,则显示第一次运行屏幕;如果FetchRequestController触发并有数据,则将其删除
导入联合收割机
导入CoreData
@可用(iOS 14.0,*)
类同步监视器{
///我们为正在收听的发布者存储组合可取消内容,例如NSPersistentCloudKitContainer的通知。
fileprivate var disposables=Set()
init(){
NotificationCenter.default.publisher(用于:NSPersistentCloudKitContainer.eventChangedNotification)
.sink(receiveValue:{中的通知
如果让cloudEvent=notification.userInfo?[NSPersistentCloudKitContainer.eventNotificationUserInfoKey]
Post
----
content: String
Content
-------
post: Post
contribution: String
let launchedBefore = UserDefaults.standard.bool(forKey: "launchedBefore")
if launchedBefore {
print("Not first launch.")
} else {
print("First launch, setting UserDefault.")
UserDefaults.standard.set(true, forKey: "launchedBefore")
}