Core Data + CloudKit не подключается к CloudKit - PullRequest
0 голосов
/ 13 июля 2020

Я обновляю приложение Core Data до iOS13, чтобы использовать синхронизацию Core Data + CloudKit для поддержки отдельных пользователей на нескольких устройствах. Синхронизация должна происходить автоматически, и на промежуточном этапе моей разработки она действительно сработала. Теперь он не работает, поскольку телеметрия CloudKit не регистрирует никаких действий, и я не могу понять, почему он не работает.

В моих предыдущих версиях приложения я предоставил небольшое количество строк меток в UserDefaults и разрешил пользователям измените их, поместив обновленные версии обратно в UserDefaults. Это был ярлык, чтобы избежать необходимости управлять вторым объектом Core Data для небольшого количества объектов.

С тех пор я понял, что это не будет работать в реализации с несколькими устройствами, потому что факт То, что локальная база данных Core Data пуста, больше не означает, что этот пользователь использует ее впервые. Вместо этого каждое новое устройство должно обращаться к облачному источнику данных, чтобы найти строки меток, используемых пользователем, и использовать значения по умолчанию, предоставленные приложением, только если у пользователя еще нет чего-то другого.

Я следовал инструкциям Apple по настройке основных данных с помощью CloudKit , и сначала синхронизация работала нормально. Но затем я понял, что поведение синхронизации было неправильным, и что вместо предварительного заполнения из строк, хранящихся в UserDefaults, мне действительно нужно было предоставить предварительно заполненную базу данных Core Data (файлы .sqlite). Я реализовал это, и теперь приложение отлично работает локально после копирования связанных файлов .sqlite при первом локальном запуске.

Но по какой-то причине из-за этого изменения синхронизация CloudKit перестала работать. Теперь я не только не получаю никаких автоматических обновлений на других устройствах, но и не получаю результатов в телеметрии панели управления CloudKit, поэтому похоже, что синхронизация CloudKit никогда не запускается. Это странно, потому что локально я получаю уведомления об «удаленных» изменениях, которые только что произошли локально (функция, которую я указываю как #selector для уведомления, вызывается локально, когда я сохраняю новые данные локально).

I ' m озадачен, в чем проблема / решение. Вот мой соответствующий код.

//In my CoreDataHelper class
lazy var context = persistentContainer.viewContext

lazy var persistentContainer: NSPersistentCloudKitContainer = {

    let appName = Bundle.main.infoDictionary!["CFBundleName"] as! String
    let container = NSPersistentCloudKitContainer(name: appName)
    
    //Pre-load my default Core Data data (Category names) on first launch
    let storeUrl = FileManager.default.urls(for: .applicationSupportDirectory, in:.userDomainMask).first!.appendingPathComponent(appName + ".sqlite")
    let storeUrlFolder = FileManager.default.urls(for: .applicationSupportDirectory, in:.userDomainMask).first!

    if !FileManager.default.fileExists(atPath: (storeUrl.path)) {
        let seededDataUrl = Bundle.main.url(forResource: appName, withExtension: "sqlite")
        let seededDataUrl2 = Bundle.main.url(forResource: appName, withExtension: "sqlite-shm")
        let seededDataUrl3 = Bundle.main.url(forResource: appName, withExtension: "sqlite-wal")

        try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl)
        try! FileManager.default.copyItem(at: seededDataUrl2!, to: storeUrlFolder.appendingPathComponent(appName + ".sqlite-shm"))
        try! FileManager.default.copyItem(at: seededDataUrl3!, to: storeUrlFolder.appendingPathComponent(appName + ".sqlite-wal"))
    }

    let storeDescription = NSPersistentStoreDescription(url: storeUrl)
    storeDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)

    //In the view controllers, we'll listen for relevant remote changes
    let remoteChangeKey = "NSPersistentStoreRemoteChangeNotificationOptionKey"
    storeDescription.setOption(true as NSNumber, forKey: remoteChangeKey)

    container.persistentStoreDescriptions = [storeDescription]
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    
    //This is returning nil but I don't think it should
    print(storeDescription.cloudKitContainerOptions?.containerIdentifier)
    
    return container
}()

//In my view controller

let context = CoreDataHelper.shared.context

override func viewDidLoad() {
    super.viewDidLoad()
    
    //Do other setup stuff, removed for clarity
    
    //enable CloudKit syncing
    context.automaticallyMergesChangesFromParent = true
}

override func viewWillAppear(_ animated: Bool) {
    clearsSelectionOnViewWillAppear = splitViewController!.isCollapsed
    super.viewWillAppear(animated)
    
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(reportCKchange),
        name: NSNotification.Name(
            rawValue: "NSPersistentStoreRemoteChangeNotification"),
        object: CoreDataHelper.shared.persistentContainer.persistentStoreCoordinator
    )
    updateUI()
}

@objc
fileprivate func reportCKchange() {
    print("Change reported from CK")
    tableView.reloadData()
}

Примечание: я обновил цель до iOS13 +.

1 Ответ

1 голос
/ 13 июля 2020

Я думаю, что недавно созданный NSPersistentStoreDescription не имеет cloudKitContainerOptions по умолчанию.

Чтобы установить их, попробуйте:

storeDescription.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: <<Your CloudKit ID>>)

...