Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

168
Visualizações
¿Es posible volver a fallar las propiedades/columnas seleccionadas de un NSManagedObject para optimizar el uso de la memoria?

Actualmente, tengo una aplicación de notas, que estoy usando la siguiente estructura CoreData.

 extension Note { @nonobjc public class func fetchRequest() -> NSFetchRequest<Note> { return NSFetchRequest<Note>(entityName: "Note") } @NSManaged public var heavy_body: String? @NSManaged public var lite_title: String? @NSManaged public var uuid: UUID? }

Solo obteniendo la columna lite_title para preservar el uso de la memoria

Al mostrar cientos o miles de notas simultáneamente en una UICollectionView , solo necesito mostrar lite_title . Esto es para minimizar el uso de la memoria. Aquí está el código para lograr tal objetivo.

El siguiente código solo cargará todos los lite_title de Notes en la memoria, pero NO heavy_body .

 private lazy var fetchedResultsController: NSFetchedResultsController<Note> = { let fetchRequest: NSFetchRequest<Note> = Note.fetchRequest() // We will NOT fetch "heavy_body" explicitly during app start, because it is a heavy resource. fetchRequest.propertiesToFetch = [ "lite_title" ] fetchRequest.sortDescriptors = [ NSSortDescriptor(key: "lite_title", ascending: false) ] // Create a fetched results controller and set its fetch request, context, and delegate. let controller = NSFetchedResultsController( fetchRequest: fetchRequest, managedObjectContext: CoreDataStack.INSTANCE.persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil ) controller.delegate = self return controller }()

Intente obtener heavy_body para 1 nota, luego, con suerte, podrá descartar heavy_body de la memoria

Durante la edición de 1 nota, esto es lo que termino de lograr

  1. Intentar leer lite_title no activará la operación SQLite DB, porque lite_title ya está en la memoria
  2. El intento de leer heavy_body activará la operación SQLite DB, porque heavy_body aún no se recupera en la memoria debido a la exclusión de fetchRequest.propertiesToFetch
  3. Para eliminar heavy_body de la memoria, llame a note.managedObjectContext?.refresh(note, mergeChanges: false) para convertirlo en error. Con suerte, junto con la información de fetchRequest.propertiesToFetch , CoreData es lo suficientemente inteligente como para darse cuenta, solo necesita "fallar" heavy_body , pero dejar lite_title intacto.

Escribimos el siguiente código para lograr los objetivos anteriores.

 @IBAction func readData(_ sender: Any) { guard let sections = self.fetchedResultsController.sections else { return } guard let note = sections[0].objects?[0] as? Note else { return } if note.isFault { print(">>>> This is a fault.\n") } else { print(">>>> This is NOT a fault.\n") } print(">>>> Read lite_title\n") let lite_title = note.lite_title print(">>>> After accessing lite_title, isFault is \(note.isFault)\n") print(">>>> Read heavy_body\n") let heavy_body = note.heavy_body print(">>>> After accessing heavy_body, isFault is \(note.isFault)\n") // Move the object back to fault. note.managedObjectContext?.refresh(note, mergeChanges: false) print(">>>> After moving object back to fault, isFault is \(note.isFault)\n") }

El primer intento parece funcionar como se esperaba

Nuestra primera ejecución parece funcionar como se esperaba. Obtenemos el siguiente registro

 >>>> This is a fault. >>>> Read lite_title >>>> After accessing lite_title, isFault is true >>>> Read heavy_body CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZHEAVY_BODY, t0.ZLITE_TITLE, t0.ZUUID FROM ZNOTE t0 WHERE t0.Z_PK = ? CoreData: details: SQLite bind[0] = (int64)1 CoreData: annotation: sql connection fetch time: 0.0003s CoreData: annotation: fetch using NSSQLiteStatement <0x600002151040> on entity 'Note' with sql text 'SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZHEAVY_BODY, t0.ZLITE_TITLE, t0.ZUUID FROM ZNOTE t0 WHERE t0.Z_PK = ? ' returned 1 rows CoreData: annotation: with values: ( "<NSSQLRow: 0x600000c00b40>{Note 1-1-5 heavy_body=\"the body, which is a heavy resource\" lite_title=\"the title\" uuid=F80CE382-0345-49A0-AD34-2BAF317AB0C0 and to-manys=0x0}" ) CoreData: annotation: total fetch execution time: 0.0006s for 1 rows. CoreData: annotation: fault fulfilled from database for : 0xbee59927ca0b4c5b <x-coredata://DBF3953E-6ABA-4542-9F79-89822F537A93/Note/p1> with row values: <NSSQLRow: 0x600000c00b40>{Note 1-1-5 heavy_body="the body, which is a heavy resource" lite_title="the title" uuid=F80CE382-0345-49A0-AD34-2BAF317AB0C0 and to-manys=0x0} >>>> After accessing heavy_body, isFault is false >>>> After moving object back to fault, isFault is true

Parece lograr nuestro objetivo

  1. Read lite_title no activará la operación SQLite DB.
  2. Leer heavy_body activará la operación SQLite DB.

Sin embargo, no estamos seguros después de note.managedObjectContext?.refresh(note, mergeChanges: false) , ¿se descarta heavy_body de la memoria? Aunque isFault devuelve verdadero, solo podemos confirmarlo ejecutando la misma función por segunda vez


2do intento no funciona

Ejecutamos la misma función por segunda vez. Este es nuestro registro

 >>>> This is a fault. >>>> Read lite_title >>>> After accessing lite_title, isFault is false >>>> Read heavy_body >>>> After accessing heavy_body, isFault is false >>>> After moving object back to fault, isFault is true

Aunque isFault es verdadero, pero no se observó ninguna operación de SQLite DB, cuando leemos heavy_body . ¡Parece que heavy_body todavía permanece en la memoria caché de CoreData!


Nos gustaría eliminar heavy_body de la memoria y dejar lite_title intacto para este caso.

O, incluso si lite_title se elimina de la memoria, al acceder a note.lite_title y desencadenar la activación de fallas, solo lite_title debe recuperarse en SQLite (como se indica en propertiesToFetch , solo queremos que se lite_title ). heavy_body NO debe buscarse en SQLite a lo largo del costado.

¿Puedo saber cómo puedo lograrlo?

El código de muestra completo para demostrar el problema está en https://github.com/yccheok/faulting-example

Referencia: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/FaultingandUniquing.html (Devolver el objeto a la falla)


Actualización sobre la desactivación del mecanismo de almacenamiento en caché en CoreData

Según la sugerencia de @Eugene Dudnyk, pude desactivar el mecanismo de almacenamiento en caché de CoreData usando

 container.viewContext.stalenessInterval = 0.1

Con dicho código, puedo observar la recuperación de SQLite en el segundo intento.

 >>>> This is a fault. >>>> Read lite_title CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZHEAVY_BODY, t0.ZLITE_TITLE, t0.ZUUID FROM ZNOTE t0 WHERE t0.Z_PK = ? CoreData: details: SQLite bind[0] = (int64)1 CoreData: annotation: sql connection fetch time: 0.0002s CoreData: annotation: fetch using NSSQLiteStatement <0x600002b80320> on entity 'Note' with sql text 'SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZHEAVY_BODY, t0.ZLITE_TITLE, t0.ZUUID FROM ZNOTE t0 WHERE t0.Z_PK = ? ' returned 1 rows CoreData: annotation: with values: ( "<NSSQLRow: 0x6000006991a0>{Note 1-1-6 heavy_body=\"the body, which is a heavy resource\" lite_title=\"the title\" uuid=F80CE382-0345-49A0-AD34-2BAF317AB0C0 and to-manys=0x0}" ) CoreData: annotation: total fetch execution time: 0.0008s for 1 rows. CoreData: annotation: fault fulfilled from database for : 0x9aff7ac6eceb6a90 <x-coredata://DBF3953E-6ABA-4542-9F79-89822F537A93/Note/p1> with row values: <NSSQLRow: 0x6000006991a0>{Note 1-1-6 heavy_body="the body, which is a heavy resource" lite_title="the title" uuid=F80CE382-0345-49A0-AD34-2BAF317AB0C0 and to-manys=0x0} >>>> After accessing lite_title, isFault is false >>>> Read heavy_body >>>> After accessing heavy_body, isFault is false >>>> After moving object back to fault, isFault is true

Sin embargo, todavía hay una trampa.

Al leer lite_title , esperaba que la obtención de datos de SQLite respetara fetchRequest.propertiesToFetch , solo lite_title .

Sin embargo, parece que los datos de SQLite están obteniendo todo el objeto Note , al obtener heavy_body también.

¿Cómo puedo evitar obtener heavy_body si solo estoy interesado en lite_title ?

Gracias.

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

CoreData tiene almacenamiento en caché subyacente. ManagedObjectContext tiene una propiedad stalenessInterval para controlar durante cuánto tiempo se debe considerar actualizada la información almacenada en caché. Puedes leer más sobre esto aquí .

El valor predeterminado de la propiedad define la obsolescencia infinita.

Para probar que marca la diferencia, agregue a CoreDataStack.swift:30 esta línea:

 container.viewContext.stalenessInterval = 0.1
over 4 years ago · Santiago Trujillo Relatório

0

Parece que todo este trabajo adicional se puede evitar si Note almacena el texto del heavy_body en un archivo por separado y solo necesita saber esa filePath del archivo.

Siempre que la aplicación necesite cargar el heavy_body completo (por ejemplo, abrir una pantalla de detalles de la Note ), lea/cargue el contenido del archivo ubicado en Note.filePath .

Tan pronto como termine de lidiar con el heavy_body , aléjese de la pantalla de detalles de la Note y el sistema se encargará de limpiarlo automáticamente.


En caso de que desee mostrar algunos metadatos sobre heavy_body en la misma UICollectionViewCell (por ejemplo, tamaño/longitud), puede almacenar metadatos adicionales en el objeto Note y mantenerlos sincronizados con los datos de heavy_body configurando/actualizando los valores apropiados en willSave() devolución de llamada.


CoreData administra su almacenamiento en caché por razones válidas y luchar contra él para que funcione en este caso podría crear más trabajo de contabilidad del necesario.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda