es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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:

  1. instanciar un nuevo NSPersistentCloudKitContainer
  2. establecer storeDescription.cloudKitContainerOptions = nil
  3. 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?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Actualización de NSPersistentCloudKitContainer durante el tiempo de ejecución en una aplicación SwiftUI con Core Data

    Siendo 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:

    1. Instanciar una nueva NSPersistentCloudKitContainer.
    2. Establecer storeDescription.cloudKitContainerOptions en nil.
    3. Cargar el almacén de persistencia.

    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:

    [error] warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'TestEntity' so +entity is unable to disambiguate.
    

    Descubrí que el problema se debía al concepto @Environment, que no estaba actualizando mi viewContext automáticamente después de volver a inicializar NSPersistentCloudKitContainer.

    Soluciones

    Para solucionar este problema y reinyectar el viewContext, introduje @Published var persistenceContainerReloaded en la clase Persistence. Cada vez que alternaba la sincronización de CloudKit, cambiaba entre NSPersistentCloudKitContainer y NSPersistentContainer. Luego aumenté el atributo persistenceContainerReloaded 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 de 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)
            }
        }
    }
    

    Sin embargo, todavía enfrenté algunos problemas con esta solución. A pesar de que storeDescription.cloudKitContainerOptions se estableció en nil, todavía veía salidas de depuración de CoreData+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 plano NSCloudKitMirroringDelegate en ejecución, subiendo cambios de CoreData.

Comments are closed.