Swift CloudKit CoreData 远程更改通知也会触发本地更改
Posted
技术标签:
【中文标题】Swift CloudKit CoreData 远程更改通知也会触发本地更改【英文标题】:Swift CloudKit CoreData Remote Change Notification also firing for local changes 【发布时间】:2020-12-07 21:57:07 【问题描述】:我有一个带有 Local 存储和 Cloud 存储的 CoreData 设置,只有后者与 CloudKit 同步。同步本身运行良好。
我正在尝试侦听远程更改通知,以便在来自 CloudKit 的远程更改进入时触发设备上的某些进程。我在持久性控制器中设置了 NSPersistentStoreRemoteChangeNotificationOptionKey
键,并设置了相应的观察者监听这个。
观察者正确触发远程更改通知,但是我的问题是 也 触发保存视图上下文后在设备上发起的任何 CoreData 更改。
如果这是预期的行为,我希望通知本身至少有一些有用的信息,以便我可以区分更改是由设备上的操作触发还是从 CloudKit 同步的。
是我做错了什么,还是有其他简单的方法可以在远程更改出现时获得通知?
持久性控制器
struct PersistenceController
static let shared = PersistenceController()
let container: NSPersistentCloudKitContainer
init()
container = NSPersistentCloudKitContainer(name: "MyContainerName")
let storeDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
// Local
let localUrl = storeDirectory.appendingPathComponent("local.store")
let local = NSPersistentStoreDescription(url: localUrl)
local.configuration = "Local"
// Cloud
let cloudUrl = storeDirectory.appendingPathComponent("cloud.store")
let cloud = NSPersistentStoreDescription(url: cloudUrl)
cloud.configuration = "Cloud"
cloud.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "my.container.identifier")
cloud.setOption(true as NSNumber, forKey: "NSPersistentStoreRemoteChangeNotificationOptionKey")
container.persistentStoreDescriptions = [local, cloud]
container.loadPersistentStores(completionHandler: (storeDescription, error) in
if let error = error as NSError?
fatalError("Unresolved error \(error), \(error.userInfo)")
)
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
应用代理
class AppDelegate: NSObject, UIApplicationDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool
NotificationCenter.default.addObserver(
self, selector: #selector(type(of: self).storeRemoteChange(_:)),
name: .NSPersistentStoreRemoteChange,
object: PersistenceController.shared.container.persistentStoreCoordinator
)
return true
@objc
func storeRemoteChange(_ notification: Notification)
precondition(notification.name == NSNotification.Name.NSPersistentStoreRemoteChange)
print(notification.userInfo)
打印语句的输出
Optional([AnyHashable("NSStoreUUID"): C2D121212-421B-003F-9819-956411111169, AnyHashable("storeURL"): file:///var/mobile/Containers/Data/Application/3234FH#-DACF-493I-AD24-143E4CDSFE2/Library/Application%20Support/cloud.store])
【问题讨论】:
【参考方案1】:如果这是预期的行为,我希望通知本身至少有一些有用的信息,以便我可以区分更改是由设备上的操作触发还是从 CloudKit 同步的。
是的,这是预期的行为,因为无论是在设备本地还是从云端更改,这都会记录为您的商店/数据库中的更改。
因此,为了处理来自云端的更改,您可以订阅数据库更改,请阅读here
【讨论】:
嗨@Stamenkovski,谢谢。我已经测试了您推荐的内容并且它有效,但是通知似乎在 CoreData 模型更新到达并生效前几秒钟到达,我假设这是正常的。我想在收到远程通知时触发一些进程,但只有在实际的 CoreData 更改进来之后。您有什么具体的建议吗? 我不能给你很好的解决方案,一种方法是让你自己同步。这意味着您可以在没有 NSPersistentCloudKitContainer 的情况下使用自定义 CKRecord,并且当发生更改时,处理更改并将 CKRecord 保存到您的自定义核心数据对象。 或在保存到核心数据之前格式化数据。以上是关于Swift CloudKit CoreData 远程更改通知也会触发本地更改的主要内容,如果未能解决你的问题,请参考以下文章
Swift3、CloudKit 和 UITableView 返回空白表
如何在 Swift 中将 Core Data 与 Cloudkit 和许多设备同步