Миграция локальных CoreData в CloudKit (и наоборот)IOS

Программируем под IOS
Ответить Пред. темаСлед. тема
Anonymous
 Миграция локальных CoreData в CloudKit (и наоборот)

Сообщение Anonymous »

Я работаю над созданием многоразового менеджера базовых данных для внутреннего пакета Swift, поэтому мне не придется полностью настраивать его каждый раз, когда мне нужно его вызвать, но я могу поддерживать согласованность во всех небольших приложениях. >
Одна вещь, которую я пытался реализовать, — это возможность миграции из локальных Core Data в контейнеры CloudKit.
Поскольку этот пакет будет использоваться на разных приложения на разных стадиях разработки, я не могу просто обновить NSPersistentContainer до NSPersistentCloudKitContainer, как показано в видео WWDC. Это приведет к тому, что некоторые приложения начнут использовать CloudKit, хотя они еще не готовы к этому, когда я начну над ним работать.
Моей целью было иметь логическое значение при настройке имени .xcdatamodeld. для моего init, в котором указано useCloud.
На данный момент он «работает», но создает две отдельные базы данных — локальную версию и версию CloudKit. .
Я имею в виду, что если я установлю: CoreDataManager.setupSharedInstance(withModelName: "CDModel", useCloud: false), я смогу создавать данные и сохранять их в локальная база данных.
Если я отредактирую эту строку на CoreDataManager.setupSharedInstance(withModelName: "test", useCloud: true), похоже, база данных будет повторно инициализирована. Затем я могу сгенерировать больше данных, которые сохранятся, и их можно будет увидеть на информационной панели.
Однако, если я снова переключу логическое значение обратно на false, я теперь увижу старые исходные данные.
Я не совсем понимаю, где в коде я напутал, и надеюсь, что свежий взгляд сможет помочь.
Я пропустил функции CRUD, так как все они, похоже, находятся в init, где и заключается моя проблема. Версия CloudKit создана таким образом, чтобы я мог использовать CKShare и некоторые области общедоступных баз данных.

Код: Выделить всё

public final class CoreDataManager {

static internal var _modelName: String!
static public var shared: CoreDataManager!

private var _privatePersistentStore: NSPersistentStore?
private var _sharedPersistentStore: NSPersistentStore?
private var _publicPersistentStore: NSPersistentStore?

public static func setupSharedInstance(withModelName modelName: String, useCloud: Bool = false) {
_modelName = modelName
shared = CoreDataManager(modelName: modelName, useCloud: useCloud)
}

internal var container: NSPersistentContainer!
internal var context: NSManagedObjectContext { container.viewContext }

private init(modelName: String, useCloud: Bool) {
if useCloud {
setupCKContainer(modelName: modelName)
} else {
setupCDContainer(modelName: modelName)
}

context.automaticallyMergesChangesFromParent = true
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

do {
try context.setQueryGenerationFrom(.current)
} catch {
fatalError("Failed to pin viewContext to the current generation: \(error)")
}
}

private func setupCKContainer(modelName: String) {
container = NSPersistentCloudKitContainer(name: modelName)
guard let privateStoreDescription = container.persistentStoreDescriptions.first else {
fatalError("Unable to configure iCloud stores: No store descriptions available.")
}
let storeDescriptionUrl = privateStoreDescription.url?.deletingLastPathComponent()
let privateStoreURL = storeDescriptionUrl?.appendingPathComponent("private.sqlite", conformingTo: .database)
privateStoreDescription.url = privateStoreURL
let sharedStoreURL = storeDescriptionUrl?.appendingPathComponent("shared.sqlite", conformingTo: .database)
let publicStoreURL = storeDescriptionUrl?.appendingPathComponent("public.sqlite", conformingTo: .database)
guard let sharedStoreDescription = privateStoreDescription.copy() as? NSPersistentStoreDescription,
let publicStoreDescription = privateStoreDescription.copy() as? NSPersistentStoreDescription else {
fatalError("Copying the private store description returned an unexpected value.")
}
sharedStoreDescription.url = sharedStoreURL
publicStoreDescription.url = publicStoreURL
guard let containerIdentifier = privateStoreDescription.cloudKitContainerOptions?.containerIdentifier else {
fatalError("Unable to get containerIdentifier")
}
let sharedStoreOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: containerIdentifier)
let publicStoreOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: containerIdentifier)
sharedStoreOptions.databaseScope = .shared
publicStoreOptions.databaseScope = .public
sharedStoreDescription.cloudKitContainerOptions = sharedStoreOptions
publicStoreDescription.cloudKitContainerOptions = publicStoreOptions
container.persistentStoreDescriptions.append(sharedStoreDescription)
container.persistentStoreDescriptions.append(publicStoreDescription)
container.loadPersistentStores { loadedStoreDescription, error in
if let error = error as NSError? {
fatalError("Failed to load persistent stores: \(error)")
}

if let cloudKitContainerOptions = loadedStoreDescription.cloudKitContainerOptions {
guard let loadedStoreDescritionURL = loadedStoreDescription.url else {
return
}

loadedStoreDescription.setOption(
true as NSNumber,
forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey
)
loadedStoreDescription.setOption(
true as NSNumber,
forKey: NSPersistentHistoryTrackingKey
)

switch cloudKitContainerOptions.databaseScope {
case .private:
let privateStore = self.container.persistentStoreCoordinator.persistentStore(for:  loadedStoreDescritionURL)
self._privatePersistentStore = privateStore
case .shared:
let sharedStore = self.container.persistentStoreCoordinator.persistentStore(for: loadedStoreDescritionURL)
self._sharedPersistentStore = sharedStore
case .public:
let publiceStore = self.container.persistentStoreCoordinator.persistentStore(for: loadedStoreDescritionURL)
self._publicPersistentStore = publiceStore
@unknown default:
fatalError("New database scope not accounted for")
}
}
}
}

private func setupCDContainer(modelName: String) {
container = NSPersistentContainer(name: modelName)
container.loadPersistentStores { loadedStoreDescription, error in
if let error = error as NSError? {
fatalError("Failed to load persistent stores: \(error)")
}
loadedStoreDescription.setOption(
false as NSNumber,
forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey
)
loadedStoreDescription.setOption(
false as NSNumber,
forKey: NSPersistentHistoryTrackingKey
)

}
}

public var ckContainer: CKContainer {
let description = container.persistentStoreDescriptions.first
guard let identifier = description?.cloudKitContainerOptions?.containerIdentifier else {
fatalError("Unable to get container identifier")
}
return CKContainer(identifier: identifier)
}

public var privatePersistentStore: NSPersistentStore {
guard let privateStore = _privatePersistentStore else {
fatalError("Private store is not set")
}
return privateStore
}

public var sharedPersistentStore: NSPersistentStore {
guard let sharedStore = _sharedPersistentStore else {
fatalError("Shared store is not set")
}
return sharedStore
}

public var publicPersistentStore: NSPersistentStore {
guard let publicStore = _publicPersistentStore else {
fatalError("Public store is not set")
}
return publicStore
}
}
Я понимаю, что это может быть не совсем традиционно, но до перехода на CloudKit рабочая часть только локальных базовых данных значительно облегчила мне разработку с помощью этого пакета. Я надеюсь, что в рамках этого проекта у меня появится возможность использовать CloudKit.


Подробнее здесь: https://stackoverflow.com/questions/782 ... vice-versa
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «IOS»