CoreData与CloudKit在watchOS上未同步

13

我已经成功地在我的iOS应用程序中使用新的NSPersistentCloudKitContainer实现了与CloudKit的CoreData集成,并使其能够在应用程序运行时自动同步。但是,当我尝试在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的同步吗?任何帮助将不胜感激。


你好!你能分享一下如何在iPhone和Apple Watch之间同步CoreData的示例吗? 我尝试过了,但是每次在Watch端都会出现认证错误(错误的bandle ID)。 - Ku6ep
3个回答

3

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

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

context.automaticallyMergesChangesFromParent = true

3
你好。欢迎来到Stack Overflow。感谢您的时间!您所写的不是对问题的回答,而是另一个问题。尽管如此,如果您能描述更改如何影响上下文的行为以及这种变化与问题陈述相关的方式,那么它可能是一个有价值的贡献。否则,这应该是一个评论,而不是一个答案。 - Lutz

3

我曾经遇到过同样的问题,但是我通过配置默认持久化存储描述来解决了这个问题,而不是定义一个新的描述:

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
    }()

你能否把你的整个代码贴出来吗?因为我在watchOS和iOS上使用iCloudSync时遇到了困难。 - BIBIN BENNY
我不确定如何邀请您聊天,但我们可以这样做,这样您可以具体告诉我您想要什么。 - rs7
谢谢回复,我在处理Apple Watch上的cloudSync时遇到了困难,后来发现模拟器上的云同步由于某种原因被阻止了。 - BIBIN BENNY
是的,我在手表模拟器上遇到了完全相同的问题。使用 iPhone/iPad 模拟器,您可以通过将应用程序移至后台并返回前台来触发同步。 - rs7
它仍然无法工作。我在苹果论坛上读到,云同步在Watch模拟器中被阻止了。 - BIBIN BENNY
是的,观察模拟器无法用于测试iCloud同步。我指的是只能在iPhone/iPad模拟器上测试iCloud同步。 - rs7

1
您尝试添加观察者吗,例如:

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接