【问题标题】:Swift CloudKit CoreData Remote Change Notification also firing for local changesSwift CloudKit CoreData 远程更改通知也会触发本地更改
【发布时间】: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])

【问题讨论】:

    标签: ios swift core-data cloudkit


    【解决方案1】:

    如果这是预期的行为,我希望通知本身至少有一些有用的信息,以便我可以区分更改是由设备上的操作触发还是从 CloudKit 同步的。

    是的,这是预期的行为,因为无论是在设备本地还是从云端更改,这都会记录为您的商店/数据库中的更改。

    因此,为了处理来自云端的更改,您可以订阅数据库更改,请阅读here

    【讨论】:

    • 嗨@Stamenkovski,谢谢。我已经测试了您推荐的内容并且它有效,但是通知似乎在 CoreData 模型更新到达并生效前几秒钟到达,我假设这是正常的。我想在收到远程通知时触发一些进程,但只有在实际的 CoreData 更改进来之后。您有什么具体的建议吗?
    • 我不能给你很好的解决方案,一种方法是让你自己同步。这意味着您可以在没有 NSPersistentCloudKitContainer 的情况下使用自定义 CKRecord,并且当发生更改时,处理更改并将 CKRecord 保存到您的自定义核心数据对象。
    • 或在保存到核心数据之前格式化数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-12
    • 1970-01-01
    • 2017-05-13
    • 2020-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多