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.

Mezclar contextos de objetos administrados padre e hijo a lo largo de una jerarquía de vistas

Estoy utilizando Core Data para persistir datos en mi aplicación y tengo una pregunta sobre cómo combinar contextos de objetos administrados principal e hijo en una jerarquía de vistas.

Para simplificar, digamos que mi aplicación permite a los usuarios crear una biblioteca de recetas que han ideado.

En la aplicación, tengo tres pantallas:

  1. LIBRERÍA: La vista de nivel superior de la “biblioteca” donde el usuario puede seleccionar diferentes recetas y tocar para editarlas o agregar una nueva receta.
  2. MODAL DE EDICIÓN/AGREGAR: La pantalla de edición/agregar que permite cambiar una receta existente o crear una nueva desde cero.
  3. POPUP DE INGREDIENTES: Un popover de selección que permite al usuario elegir de una lista de ingredientes y agregar nuevos a la lista.

Como suele ser práctica común, estoy creando un contexto hijo para la vista modal de edición/agregar para poder descartar los cambios si el usuario toca “cancelar” y solo persistirlos si se toca “guardar”.

Mi duda radica en cómo manejar el popover de ingredientes. Me gustaría que los ingredientes de esta lista se compartieran entre todas las recetas, de modo que cuando el usuario agregue un ingrediente mediante la vista modal de edición/agregar de una receta, luego pueda agregarlo a otras recetas sin tener que agregarlo a la lista nuevamente. Por supuesto, si creo nuevas instancias de “ingrediente” en el contexto hijo, se descartarán si el usuario toca “cancelar” en la vista modal de edición/agregar. Por lo tanto, actualmente estoy intentando usar el contexto principal.

No sorprende que actualmente esté viendo el siguiente error cuando toco para seleccionar un ingrediente para la receta actual:

“Intento no válido de establecer una relación ‘ingrediente’ entre objetos en contextos diferentes”.

Entonces mi pregunta es, ¿cómo puedo usar un contexto hijo para la vista modal de edición/agregar pero hacer que el popover de ingredientes use el contexto principal para que los cambios realizados en esta vista se persistan, sin importar si el usuario guarda o cancela en la vista modal de edición/agregar?

Estaría encantado de incluir algún código si es necesario, pero principalmente es una pregunta sobre las mejores prácticas. Se agradecerían ejemplos de código de posibles soluciones.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Para resolver este problema, también puedes utilizar el contexto principal para el popover de ingredientes. Aquí te explicamos cómo hacerlo:

    1. En la pantalla de la biblioteca, crea el contexto principal como de costumbre para configurar el almacenamiento de Core Data.
    2. Cuando el usuario toque para editar o agregar una receta, crea un contexto secundario para esa pantalla y establece su contexto principal como el contexto principal.
    3. Cuando el usuario toque para seleccionar un ingrediente en el popover, también pasa el contexto principal a esa pantalla.
    4. En la entidad “Ingredient”, agrega una relación a la entidad “Recipe” y establece su “regla de eliminación” como “Anular”. Esto permitirá que un ingrediente esté asociado con múltiples recetas sin ser eliminado si una de ellas se elimina.
    5. Cuando el usuario agregue un nuevo ingrediente en el popover, crea una nueva instancia de “ingrediente” en el contexto principal y establece sus propiedades según desees.
    6. Cuando el usuario agregue el mismo ingrediente a una receta, crea una nueva relación entre la receta y el ingrediente en el contexto secundario y guarda el contexto secundario. Esto no guardará el ingrediente, pero guardará la relación entre la receta y el ingrediente. El ingrediente se guardará cuando se guarde el contexto principal.
    7. Cuando el usuario guarde la receta, primero guarda el contexto secundario y luego guarda el contexto principal. Esto guardará tanto los cambios en la receta como en el ingrediente.

    Ejemplo de código:

    // Configurar el almacenamiento de Core Data
    let container = NSPersistentContainer(name: "Recipes")
    container.loadPersistentStores { (storeDescription, error) in
        if let error = error {
            print("Error al cargar el almacenamiento: \(error)")
        } else {
            print("Almacenamiento cargado correctamente")
        }
    }
    
    // Crear el contexto principal
    let parentContext = container.viewContext
    
    // Cuando el usuario toque para editar o agregar una receta
    let childContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    childContext.parent = parentContext
    
    // Cuando el usuario toque para seleccionar un ingrediente en el popover
    let ingredientSelectionViewController = IngredientSelectionViewController()
    ingredientSelectionViewController.context = parentContext
    
    // Agregar un nuevo ingrediente en el popover
    let newIngredient = NSEntityDescription.insertNewObject(forEntityName: "Ingredient", into: parentContext) as! Ingredient
    newIngredient.title = "Nuevo ingrediente"
    newIngredient.quantity = 1
    
    // Asociar el ingrediente con la receta
    let receta = childContext.object(with: recipeID) as! Recipe
    let ingrediente = parentContext.object(with: ingredientID) as! Ingredient
    recipe.addToIngredients(ingredient)
    
    // Guardar los cambios
    do {
        try childContext.save()
        try parentContext.save()
    } catch {
        print("Error al guardar el contexto: \(error)")
    }
    

    Nota: Es importante guardar el contexto secundario primero y luego el contexto principal para evitar conflictos de fusión.

Comments are closed.