10

我已经设法让 CoreData 与 CloudKit 在我的应用程序的 iOS 版本上与新的 NSPersistentCloudKitContainer 一起工作,并让它在应用程序运行时自动同步。但是,当我在 watchOS 应用程序上进行设置时,我注意到只有在我强制关闭并重新打开手表应用程序时才会发生同步。

import Foundation
import CoreData

class DataManager : NSObject {
    static let shared = DataManager()

    #if os(watchOS)
    let transactionAuthorName = "watchOSApp"
    #else
    let transactionAuthorName = "iOSApp"
    #endif

    override private init() {
        super.init()
    }

    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentCloudKitContainer(name: "Model")

        let cloudStoreUrl = applicationDocumentDirectory()!.appendingPathComponent("product.sqlite")

        let cloudStoreDescription = NSPersistentStoreDescription(url: cloudStoreUrl)
        cloudStoreDescription.shouldInferMappingModelAutomatically = true
        cloudStoreDescription.shouldMigrateStoreAutomatically = true
        cloudStoreDescription.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier:"iCloud.com.company.product")

        container.persistentStoreDescriptions = [cloudStoreDescription]

        container.loadPersistentStores(completionHandler: { storeDescription, error in
            if let error = error as NSError? {
                print("Error loading store. \(error)")
            }
        })

        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        container.viewContext.automaticallyMergesChangesFromParent = true

        try? container.viewContext.setQueryGenerationFrom(.current)
        container.viewContext.transactionAuthor = transactionAuthorName

        return container
    }()
}

// MARK: - Core Data
extension DataManager {

    func applicationDocumentDirectory() -> URL? {
        return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier:"group.shiningdevelopers.h2o")
    }

    func managedObjectContext() -> NSManagedObjectContext {
        return persistentContainer.viewContext
    }

    func reset() {
        managedObjectContext().reset()
    }

    func saveContext () {
        let context = managedObjectContext()
        if context.hasChanges {
            do {
                try context.save()
            } catch let error as NSError {
                // Replace this implementation with code to handle the error appropriately.
                // Log this error for now to be able to glean more information
                print("Could not save. \(error), \(error.userInfo)")
            }
        }
    }
}

以下场景有效 - 用户同时运行 watchOS 应用程序和 iOS 应用程序 - 用户更改手表应用程序上的数据 - 更改反映在 iOS 应用程序上 - 用户仅运行 iOS 应用程序 - 用户更改为iOS 应用程序上的数据 - 用户从终止状态打开 watchOS 应用程序 - 更改反映在 watchOS 应用程序上

以下场景不起作用 - 用户正在运行 watchOS 应用程序并且正在运行 iOS 应用程序 - 用户对 iOS 应用程序上的数据进行了更改 - 即使在等待很长时间后,也没有任何更改能够通过 watchOS 应用程序 - 仅如果我强制关闭应用程序并重新启动,是否会发生同步

在同步成功的情况下,我可以正确看到以下日志:

CoreData: debug: CoreData+CloudKit: 
-[PFCloudKitImporterZoneChangedWorkItem newMirroringResultByApplyingAccumulatedChanges:]_block_invoke_2(243): <PFCloudKitImporterZoneChangedWorkItem: 0x16530fb0> { ( "<CKRecordZoneID: 0x1656a920; zoneName=com.apple.coredata.cloudkit.zone, ownerName=__defaultOwner__>" ) } - Importing updated records: ( "<CKRecord: 0x16526280; recordType=CD_LogEntry, values={\n "CD_day" = 15;\n "CD_entityName" = LogEntry;\n "CD_glassesGoal" = 8;\n "CD_glassesLogged" = 13;\n "CD_lastModified" = "2019-09-15 18:56:08 +0000";\n "CD_month" = 9;\n "CD_year" = 2019;\n}, recordChangeTag=7d, recordID=2180D6A3-ACFC-4421-8CAF-6EE288DAAC2E:(com.apple.coredata.cloudkit.zone:defaultOwner)>" ) Deleted RecordIDs: {
}

然而,在最后一个场景中,我没有看到任何日志,它完全安静。我在应用程序的 iOS 和 watchOS 版本中共享相同的 CoreData/CloudKit 代码。我还使用 NSFetchedResultsController 来确保我的 UI 保持最新,并且它似乎在 iOS 应用程序上运行,而不是在 watchOS 应用程序上运行。不确定在设置手表扩展时是否遗漏了一些步骤。

有没有人同步到 watchOS 才能工作?任何帮助,将不胜感激。

4

3 回答 3

2

您是否已context.automaticallyMergesChangesFromParent在 UI 上下文中启用?

let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

context.automaticallyMergesChangesFromParent = true
于 2019-12-26T21:04:05.667 回答
2

我遇到了同样的问题,我可以通过配置默认的持久存储描述而不是定义新的描述来解决它:

lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentCloudKitContainer(name: "Model")
        // Change this variable instead of creating a new NSPersistentStoreDescription object
        guard let description = container.persistentStoreDescriptions.first else {
            fatalError("No Descriptions found")
        }

        let cloudStoreUrl = applicationDocumentDirectory()!.appendingPathComponent("product.sqlite")

        description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
        description.setOption(true as NSObject, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
        description.url = cloudStoreUrl

        container.loadPersistentStores(completionHandler: { storeDescription, error in
            if let error = error as NSError? {
                print("Error loading store. \(error)")
            }
        })

        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        container.viewContext.automaticallyMergesChangesFromParent = true

        try? container.viewContext.setQueryGenerationFrom(.current)
        container.viewContext.transactionAuthor = transactionAuthorName

        return container
    }()
于 2020-01-05T20:34:26.353 回答
1

您是否尝试过添加观察者,例如:

// Observe Core Data remote change notifications.
    NotificationCenter.default.addObserver(
        self, selector: #selector(type(of: self).storeRemoteChange(_:)),
        name: .NSPersistentStoreRemoteChange, object: container)

然后观察观察者的变化并在那个时候进行 UI 更新?

于 2019-10-20T16:36:38.000 回答