2011-06-21 15 views
8

Tengo una aplicación de iOS con mucha memoria y estoy trabajando para asegurarme de que el uso de la memoria no se acumule con el tiempo. Mi aplicación tiene un contexto "principal" que dura toda la vida de la aplicación, y otros contextos más pequeños se generan ocasionalmente para las tareas en segundo plano.Evitar la acumulación de objetos registrados (memleak) en NSManagedObjectContext

Una cosa que he notado es que los objetos NSManagedObjects parecen permanecer registrados en el contexto principal a largo plazo y la única forma de reclamar verdaderamente toda la memoria asociada al retiro de objetos del DB es llamar al [NSManagedObjectContext reset].

Por supuesto, esto produce una buena reducción en el uso de la memoria ya que todos los objetos registrados de vistas de listas cerradas recientemente se expulsan correctamente de la memoria, sin embargo es molesto porque acaba de invalidar cada objeto registrado en ese contexto que usted todavía tiene una referencia a (es decir, objetos a los que se refieren las vistas que todavía están abiertas), y ahora necesita volver a buscar todos estos objetos de la base de datos para evitar excepciones para acceder a un objeto invalidado.

Es esta la única forma de eliminar el conjunto de objetos registrados de un NSManagedObjectContext, o existe una forma mejor de expulsar correctamente todos los objetos registrados a los que ya no tiene referencias, pero no invalida todos los objetos NSManagedObjects ¿Aún vivo?

Respuesta

12

NSManagedObjectContext tiene un caché de fila interno, y la única forma de que pueda borrar eso es restablecer el contexto. Si realmente tiene problemas de memoria, algunas cosas que pueden ayudar son:

  • Los objetos administrados conservan sus objetos relacionados. Si tiene el objeto gestionado A al que hace referencia una relación de otro objeto gestionado B, el objeto A permanecerá en la memoria incluso si ha liberado todas las referencias al mismo. En realidad, no se desasignará hasta que el objeto B se desasigne o vuelva a generar una falla, porque aún se conservará en B.
  • Una forma de resolver esto (y otros problemas de memoria) es llamando al refreshObject:mergeChanges: en el MOC para objetos que no está utilizando actualmente, con el segundo argumento establecido en NO. Eso restablece la falla del objeto, es decir, hace que el objeto regrese al estado inicial de "falla", descargando sus valores de propiedad y sus relaciones. Con A y B de antes, volver a fallar B liberaría la relación a A. Tenga en cuenta que esto perderá los cambios no guardados en B, por lo que debe asegurarse de haberlos guardado primero si es necesario.
  • Si sus objetos administrados contienen algún tipo de datos binarios grandes, intente mover esos datos a una entidad separada o fuera de los Datos principales para evitar cargarlos en la memoria cuando no los necesite.
  • reset en el MOC es básicamente la opción nuclear cuando se trata de la administración de la memoria de Core Data. Es extremadamente efectivo, pero como has encontrado puede ser muy peligroso. Lo mejor es evitarlo a menos que ya no esté utilizando ningún objeto cargado desde el MOC.
+0

Hola Tom: gracias por la gran respuesta. De todas sus opciones, la única que pensé que podría ayudar fue 'refreshObject: mergeChanges:', y cuando lo probé llamándolo a todos los objetos en una vista de lista cuando se destruyó la vista de lista, desafortunadamente no parece tener mucho impacto. Supongo que el caché de filas es lo que está consumiendo a todos los miembros, así que a menos que haya otra manera de borrar el caché de filas, supongo que todavía tendré que hacer la ruta de 'reinicio'. Bummer :( – glenc

+0

¿Estás recibiendo advertencias de memoria? Nunca dijiste. Si no lo eres, entonces restablecer el contexto es completamente innecesario. –

+0

Sí, recibo advertencias de memoria.Depende del tamaño de la base de datos que se use, pero sí definitivamente sucede. – glenc

Cuestiones relacionadas