Cómo alternar la sincronización de CoreData y CloudKit durante la ejecución de la App.
Actualmente estoy desarrollando una aplicación basada en SwiftUI con sincronización de Core Data y CloudKit mediante NSPersistentCloudKitContainer
.
Encontré diferentes soluciones sobre cómo alternar la sincronización de CloudKit de Core Data durante la ejecución, también aquí en Stack Overflow. La idea básica de estas soluciones es la siguiente:
- instanciar un nuevo
NSPersistentCloudKitContainer
- establecer
storeDescription.cloudKitContainerOptions = nil
- cargar el almacén de persistencia
La mayoría de las soluciones recomiendan reiniciar la aplicación manualmente para evitar exactamente mi problema descrito a continuación.
Problemas:
Hasta aquí todo bien. ¿Cómo puedo distribuir el nuevo viewContext
en mi aplicación SwiftUI durante la ejecución? En la aplicación principal distribuí el viewContext
durante el inicio a través de @Environment(\.managedObjectContext)
y parece que no se actualiza automáticamente después de una reinicialización de NSPersistentCloudKitContainer.
var body: some Scene {
WindowGroup {
ContentView()
.environment(.managedObjectContext, persistence.container.viewContext)
}
}
Después de desactivar la sincronización de CloudKit, recibo el siguiente error cuando intento agregar una nueva entidad.
warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'TestEntity' so +entity is unable to disambiguate.
¿Alguna idea? ¿Es un problema del concepto de @Environment
?
Actualización: 12.12.2021: Se solucionó la reinsersión del viewContext
Solucioné el problema de reinsersión del viewContext
con los siguientes cambios.
Primero introduje el atributo @Published var persistenceContainerReloaded: Int = 0
en la clase Persistence
. Cada vez que alterno la sincronización de CloudKit, cambio entre NSPersistentCloudKitContainer
y NSPersistentContainer
. Luego aumento el atributo persistenceContainerReloaded
en 1. La línea .id(persistence.persistenceContainerReloaded)
activa la recarga de toda la jerarquía de vistas. Ahora cada vista utiliza la instancia correcta del viewContext
.
“`@main
struct TargetShooterApp: App {
@StateObject var persistence: Persistence = Persistence.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(.managedObjectContext, persistence.container.viewContext)
.id(persistence.persistenceContainerReloaded)
}
}
}
“`
Pero todavía enfrento algunos problemas con mi solución. Todavía veo salidas de depuración de CoreData+CloudKit en la terminal, aunque el storeDescription.cloudKitContainerOptionsis
nulo. El dispositivo aún es capaz de sincronizar cambios locales con otros dispositivos, pero no es capaz de recibir cambios realizados en otros dispositivos. Después de reiniciar la aplicación, todo funciona como se esperaba. Parece que sigue ejecutándose un proceso en segundo plano NSCloudKitMirroringDelegate
cargando cambios de CoreData. ¿Alguna idea?
davy.ai
Actualización de
NSPersistentCloudKitContainer
durante el tiempo de ejecución en una aplicación SwiftUI con Core DataSiendo un experto en TI especializado en Core Data, SwiftUI y CloudKit, actualmente estoy desarrollando una aplicación basada en SwiftUI con sincronización de Core Data y CloudKit utilizando
NSPersistentCloudKitContainer
.Mientras hacía esto, encontré diferentes soluciones en Stack Overflow sobre cómo alternar la sincronización de CloudKit de Core Data durante el tiempo de ejecución. La idea básica de estas soluciones es:
NSPersistentCloudKitContainer
.storeDescription.cloudKitContainerOptions
ennil
.Sin embargo, la mayoría de estas soluciones recomiendan reiniciar la aplicación manualmente para evitar ciertos problemas, incluidos problemas con
viewContext
.Problemas
Después de desactivar la sincronización de CloudKit, me encontré con un error al intentar agregar una nueva entidad que decía:
Descubrí que el problema se debía al concepto
@Environment
, que no estaba actualizando miviewContext
automáticamente después de volver a inicializarNSPersistentCloudKitContainer
.Soluciones
Para solucionar este problema y reinyectar el
viewContext
, introduje@Published var persistenceContainerReloaded
en la clasePersistence
. Cada vez que alternaba la sincronización de CloudKit, cambiaba entreNSPersistentCloudKitContainer
yNSPersistentContainer
. Luego aumenté el atributopersistenceContainerReloaded
en 1. La línea.id(persistence.persistenceContainerReloaded)
provocó la recarga de toda la jerarquía de vistas, asegurando así que cada vista utilizara la instancia correcta deviewContext
.Sin embargo, todavía enfrenté algunos problemas con esta solución. A pesar de que
storeDescription.cloudKitContainerOptions
se estableció ennil
, todavía veía salidas de depuración deCoreData+CloudKit
en la terminal. El dispositivo también podía sincronizar cambios locales con otros dispositivos, pero no podía recibir cambios hechos en otros dispositivos. Después de reiniciar la aplicación, todo funcionó igual que se esperaba. Parecía que todavía había un proceso en segundo planoNSCloudKitMirroringDelegate
en ejecución, subiendo cambios de CoreData.