Acceso concurrente a Core Data

Autor: | Última modificación: 25 de octubre de 2022 | Tiempo de Lectura: 2 minutos
Temas en este post:

Core Data no es seguro en multihebra

Al igual que UIKit, CoreData no es seguro en un entorno multihebra. Esto es algo que en las charlas del WWDC se repite hasta la saciedad y más allá. Lógicamente, esto no quiere decir que no se pueda acceder a CoreData desde otra hebra que no sea la principal.

Lo que quiere decir, es que solo podemos acceder a CoreData desde la hebra en que se haya creado el NSManagedObjectContext.

Es decir, si el NSManagedObjectContext ha sido creado en la hebra principal, solo podremos acceder a él desde la hebra principal. Si por el contrario, ha sido creado en otra hebra, solo podremos acceder a él desde dicha hebra.

Una fuente de confusión común, es pensar que dado que NSManagedObjectContext tiene un método performBlock:, dicho bloque se ejecutará en segundo plano. ¡Craso error! Lo que nos asegura performBlock: es que dicho bloque se ejecutará siempre en la hebra adecuada (independientemente desde cual enviemos el mensaje).

Truco para acceso concurrente a Core Data con parentContext

Por lo visto, parece que la única solución para tener un acceso concurrente a Core Data es crear el NSManagedObjectContext en otra hebra. No obstante, existe una alternativa más sencilla.

Todo NSManagedObjectContext tiene una propiedad llamada parentContext.  Dicho parentContext es otro NSManagedObjectContext que a menudo tiene su propia hebra.

Por lo tanto, lo más sencillo es crear tu propio NSManagedObjectContext como siempre, y enviar el mensaje performBlock: a su parentContext.

Eso sí, hay que tener en cuenta que son dos contextos diferentes, así que las alteraciones hechas en uno no se propagarán de forma automágica al otro. Después de modificar la base de datos vía parentContext, tendremos que guardar y hacer un refetch desde el contexto hijo.

Recomendación

CoreData es muy rápido y , por lo general, no suele ser un gran problema usarlo en la hebra principal. Intenta primero sin multihebra y sólo si ves que ese es tu cuello de botella, utiliza parentContext para el acceso concurrente.