objective c - ¿La forma más rápida de verificar si un objeto existe en Core Data o no?
objective-c iphone (4)
Quiero ver si un objeto persiste en Core Data o no. Por ejemplo, tengo Amigos en Core Data, y los identifico por firstName. Puedo consultar datos básicos para ver si se conoce a "George". Si la matriz del conjunto de resultados contiene más de cero objetos, sé que George está allí. Pero Core Data carga todo en la memoria, y en realidad solo quiero saber si George está almacenado o no.
¿Cómo lo haría de la manera más eficiente?
Configure una solicitud de Datos básicos y, en lugar de emitir realmente la consulta, haga lo siguiente:
NSError *error = nil;
NSUInteger count = [managedObjectContext countForFetchRequest:request
error:&error];
if (!error) {
return count;
} else {
return 0;
}
En la práctica, el método countForFetchRequest:error:
devuelve el número de objetos que una solicitud de recuperación dada habría devuelto si se hubiera pasado a executeFetchRequest:error:
Editar: (por Regexident)
Como Josh Caswell comentó correctamente, la forma correcta de manejar los errores es esta:
if (count == NSNotFound) {
NSLog(@"Error: %@", error);
return 0;
}
return count;
o esto (sin registro de errores):
return (count != NSNotFound) ? count : 0;
De acuerdo con la Documentación de Datos Básicos , no debe seguir buscando para ver si existen objetos.
Hay muchas situaciones en las que puede necesitar encontrar objetos existentes (objetos ya guardados en una tienda) para un conjunto de valores de entrada discretos. Una solución simple es crear un bucle, luego, para cada valor, ejecutar una búsqueda para determinar si hay un objeto persistente coincidente, y así sucesivamente. Este patrón no escala bien Si perfila su aplicación con este patrón, normalmente encontrará que la búsqueda es una de las operaciones más caras del ciclo (en comparación con solo iterar sobre una colección de elementos). Peor aún, este patrón convierte un problema O (n) en un problema O (n ^ 2).
Editar 16 de marzo :
No soy un experto en DB, pero como la gente está pidiendo una solución más eficiente, considere este conjunto:
set1 = [apple, orange, banana, pineapple, lettuce]
Queremos saber si [mango, apple, grape]
es parte de este conjunto.
Los documentos nos dicen que no debemos iterar a través de [mango, manzana, uva] y consultar la base de datos buscando cada elemento por turno porque es lento.
Considera esta solución:
Hash los conjuntos en el lado del servidor:
hash([mango, apple, grape]) = 234095dda321affe...
A continuación, puede omitir los datos principales por completo preguntando al servidor si algo cambió. Si los conjuntos son diferentes, puede volcar los objetos en un contexto de objeto administrado y hacer un guardado masivo.
Si realmente desea ver si cada objeto a su vez forma parte del conjunto, puede hacer una búsqueda basada en una característica indexada, como "fruta con piel".
Sí, definitivamente hay un mejor método. Configure una solicitud de recuperación como de costumbre, pero, en lugar de ejecutarla, simplemente solicite la cantidad de objetos que habría devuelto si se hubiera pasado a executeFetchRequest: error:
Esto se puede hacer usando
- (NSUInteger)countForFetchRequest:(NSFetchRequest *)request error:(NSError **)error;
Algo como esto:
- (int) numberOfContacts{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSManagedObjectContext *managedObjectContext = yourManagedObjectContext;
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contacts" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSError *error = nil;
NSUInteger count = [managedObjectContext countForFetchRequest:request error:&error];
[request release];
if (!error){
return count;
}
else
return -1;
}
Si el objetivo es verificar si el objeto existe, la solución es implementar este método en su Friend Model:
-(BOOL)exist
{
NSManagedObjectContext *managedObjectContext = yourManagedObjectContext;
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Friends" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
[request setFetchLimit:1];
[request setPredicate:[NSPredicate predicateWithFormat:@"firstName == %@", self.firstName]];
NSError *error = nil;
NSUInteger count = [managedObjectContext countForFetchRequest:request error:&error];
if (count)
{
return YES;
}
else
{
return NO;
}
}