Cómo hacer inserciones masivas en Core Data

En algunos casos, es necesario insertar grandes cantidades de registros en nuestra base de datos de Core Data. Utilizar context.insert dentro de un bucle for es una opción que no realiza esta operación de manera eficiente.

Core Data nos proporciona las herramientas necesarias para llevar a cabo esta tarea de manera eficiente y sencilla.

Utilizando NSBatchInsert

// 1
func insertBooks(_ books: [[String: Any]]) {
// 2
let context = persistentContainer.viewContext
// 3
let request = NSBatchInsertRequest(entity: Book.entity(), objects: books)
// 4
let result = context.execute(request)
debugPrint(result)
// 5
try? context.save()
}

Esta es la manera más simple de utilizar NSBatchInsertRequest. Para que tenga sentido utilizar NSBatchInsertRequest, imaginemos que estamos recibiendo un arreglo bastante grande.

Analicemos el código:

  1. La función acepta un array de diccionarios, los cuales deben contener los mismos nombres y tipos de datos de los atributos de nuestra entidad en Core Data.
  2. Obtenemos una referencia al contexto, NSManagedObjectContext.
  3. Creamos una instancia de NSBatchInsertRequest pasando el tipo de entidad y el arreglo de objetos que queremos insertar.
  4. Ejecutamos la operación usando execute(_:). Este método retorna el resultado de la ejecución. Imprimimos el contenido de result para obtener más información, en caso de error.
  5. Por último, llamamos save para persistir los cambios.

Insertando registros de manera eficiente

El código visto anteriormente funciona; sin embargo, podemos mejorarlo para asegurarnos de contar con un mejor rendimiento y evitar bloquear el contexto principal. Veamos una versión mejorada:

func insertBooks(_ books: [[String: Any]]) async throws {
let persistentContainer = PersistenceController.shared.container
let viewContext = persistentContainer.viewContext
// 1
let childContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
childContext.parent = viewContext
// 2
try await childContext.perform {
// 3
let batchInsertRequest = NSBatchInsertRequest(entity: Item.entity(), objects: books)
batchInsertRequest.resultType = .statusOnly
let result = try childContext.execute(batchInsertRequest)
debugPrint(result)
try childContext.save()
}
// 5
try await viewContext.perform {
try viewContext.save()
}
}

Veamos lo que hace este código:

  1. Creamos childContext, que es un contexto hijo que utiliza concurrencia. Indicamos que es un contexto hijo de viewContext. Esto nos permite realizar operaciones sin bloquear el contexto principal.
  2. Utilizamos perform para garantizar que lo ejecutado dentro del bloque de código a continuación no bloquee el hilo principal.
  3. Creamos nuestra operación de inserción e indicamos que para el resultado solo nos interesa el estado de la ejecución. Otras opciones que podemos utilizar son count y objectIDs, que retornan la cantidad de registros afectados o las Ids de los objetos afectado, respectivamente.
  4. Ejecutamos la inserción masiva y persistimos los cambios en nuestro contexto hijo.
  5. Por último, nos aseguramos de que los cambios también se persistan en el contexto padre.

Core Data nos ofrece APIs con el nuevo modelo de concurrencia moderna (async/await), sin embargo, tambien podemos utilizar estas funcionalidades si nuestro código no usa async/await.

Con esto, tenemos un código eficiente y que garantiza un buen rendimiento.

Comparte este artículo

Subscríbete a nuestro Newsletter

Mantente al día en el mundo de las aplicaciones móviles con nuestro blog especializado.

Artículos semanales

Todas las semanas artículos nuevos sobre el mundo de las aplicaciones móviles.

No spam

No te enviaremos spam, solo contenido de calidad. Puedes darte de baja cuando quieras.

Contenido de calidad

Nada de contenido generado de manera automática usando ChatGPT.

Recomendaciones

Tips indispensables sobre mejores prácticas y metodologías.

© 2024 AsyncLearn