Я обновляю приложение 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 +.