home como cerrar boton aplicaciones ios sqlite core-data watchkit ios-extensions

ios - cerrar - ¿Cómo puedo garantizar entradas únicas en un almacén de datos centrales en un contenedor de aplicaciones compartidas utilizado tanto por la aplicación de host como por una extensión?



como cerrar aplicaciones en iphone ios 10 (2)

Para hacer mi pregunta de manera efectiva, consideremos primero el escenario exacto al que me estoy enfrentando:

Configuración general

  • Una aplicación host iOS 8.
  • Una o más extensiones de iOS 8 (WatchKit, Share, etc.) incluidas con la aplicación de host.
  • La aplicación host y todas las extensiones comparten la misma tienda Coreite SQLite en el contenedor del grupo de aplicaciones compartidas.
  • Cada aplicación / extensión tiene su propio NSPersistentStoreCoordinator y NSManagedObjectContext.
  • Cada coordinador de tienda persistente utiliza una tienda persistente que comparte los mismos recursos SQLite en el contenedor de grupo como todas las otras tiendas persistentes.
  • La aplicación y todas las extensiones usan una base de código común para sincronizar contenido desde un recurso API remoto en Internet.

Secuencia de eventos que conducen al problema

  1. El usuario inicia la aplicación de host. Comienza a recuperar datos del recurso API remoto. Los objetos del modelo de datos básicos se crean en función de la respuesta de la API y se "insertan" en el contexto del objeto gestionado de la aplicación de host. Cada entidad API tiene un ID único que lo identifica en el backend API remoto. Al decir "upsert", quiero decir que para cada entidad API, la aplicación host solo crea una nueva entrada en Core Data si no se puede encontrar una entrada existente para un ID único determinado.

  2. Mientras tanto, el usuario también inicia una de las extensiones de la aplicación host. También realiza algún tipo de búsqueda desde la misma API remota. También intenta realizar un "upsert" al analizar las respuestas de la API.

  3. El problema: ¿Qué sucede si tanto la aplicación de host como la extensión intentan insertar una entrada de Datos de núcleo para la misma entidad de API al mismo tiempo? Para ver cómo podría ocurrir esto, veamos la secuencia de eventos para un postre:

Secuencia de restauración de datos principales:

  1. El código de análisis API analiza el uniqueID para una entidad de API dada.
  2. El analizador realiza una búsqueda de Datos centrales para cualquier entrada que coincida con un predicado donde uniqueID sea ​​igual al identificador único analizado.
  3. Si no se encuentra una entrada existente, el analizador inserta una nueva entrada de Datos principales para esta entidad API, establece su atributo uniqueID para la identificación única analizada.
  4. El analizador guarda el contexto del objeto administrado, que empuja los datos de la nueva entrada al almacén de respaldo de SQLite.

Problema en detalle

Supongamos que la aplicación de host y la extensión analizan de forma independiente una respuesta de API para la misma entidad de API al mismo tiempo. Si tanto la aplicación de host como la extensión alcanzan el Paso 3 antes de que cualquiera de ellos haya terminado el Paso 4, entonces ambos intentarán insertar una nueva entrada de Datos del Núcleo para la misma ID única. Cuando lleguen al Paso 4 y llamen save: en sus respectivos contextos de objetos gestionados, Core Data creará con gusto entradas duplicadas.

Hasta donde yo sé, Core Data no tiene forma de marcar un atributo como único. Necesito un Core Data equivalente a un SQLite INSERT OR IGNORE + UPDATE combo. . O bien, necesito una forma de "bloquear" la tienda de respaldo SQLite de la tienda persistente, que suena como una receta para problemas.

¿Existe un enfoque conocido para este problema bastante novedoso introducido por las extensiones de iOS 8?


¿Existe un enfoque conocido para este problema bastante novedoso introducido por las extensiones de iOS 8?

Sí, es el mismo enfoque que se aplica cuando se utiliza iCloud con Core Data: deja que los duplicados sucedan, pero luego ve a limpiarlos. Ambas situaciones corren el riesgo de crear entradas duplicadas, y no hay una manera completamente confiable de prevenirlas. Como tiene una clave uniqueID , está en buena forma en lo que respecta a esto.

Sería mucho más fácil, como señala Dave DeLong, evitar el problema en primer lugar. Si eso es imposible, puedes lidiar con eso, con algo de trabajo extra.

Encontrar duplicados sería algo así como:

NSError *error = nil; NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init]; [moc setPersistentStoreCoordinator:self.persistentStoreCoordinator]; NSFetchRequest *fr = [[NSFetchRequest alloc] initWithEntityName:@"MyEntityName"]; [fr setIncludesPendingChanges:NO]; NSExpression *countExpr = [NSExpression expressionWithFormat:@"count:(uniqueID)"]; NSExpressionDescription *countExprDesc = [[NSExpressionDescription alloc] init]; [countExprDesc setName:@"count"]; [countExprDesc setExpression:countExpr]; [countExprDesc setExpressionResultType:NSInteger64AttributeType]; NSAttributeDescription *uniqueIDAttr = [[[[[_psc managedObjectModel] entitiesByName] objectForKey:@"MyEntityName"] propertiesByName] objectForKey:@"uniqueID"]; [fr setPropertiesToFetch:[NSArray arrayWithObjects:uniqueIDAttr, countExprDesc, nil]]; [fr setPropertiesToGroupBy:[NSArray arrayWithObject:uniqueIDAttr]]; [fr setResultType:NSDictionaryResultType]; NSArray *countDictionaries = [moc executeFetchRequest:fr error:&error];

Este es prácticamente el equivalente de Core Data de algo así en SQL:

SELECT uniqueID, COUNT(uniqueID) FROM MyEntityName GROUP BY uniqueID;

Obtendrá una variedad de diccionarios, cada uno de los cuales contiene un uniqueID y un recuento del número de veces que se utiliza ese valor. Ejecuta el diccionario y trata los duplicados de forma adecuada.

Lo describí con más detalle en una publicación de blog . También hay un proyecto de muestra de Apple que muestra el proceso, llamado SharedCoreData, pero creo que solo está disponible como parte del paquete de código de muestra WWDC 2012 . También se describió en la sesión 227 en esa conferencia.


Parece que el enfoque más simple sería simplemente evitar los múltiples escritores en primer lugar. ¿Por qué no simplemente extrae por completo las extensiones de los datos en caché y luego solo actualiza su almacén de datos desde su aplicación principal de iOS?