objective c - NSFetchRequest y predicateWithBlock
objective-c core-data (2)
Estoy jugando con una aplicación que utiliza Core Data y NSManagedObjects para llenar una UITableView. Solo hay una clase en mi aplicación, llamada Event
. Creé el siguiente método de instancia personalizada en el Event
:
- (BOOL)isExpired {
return ([[self.endOn dateAtEndOfDay] timeIntervalSinceNow] < 0);
}
Me gustaría limitar la UITableView
que muestra los objetos de Event
solo a los Eventos que han expirado, es decir, donde isExpired
devuelve YES
. Intenté hacer esto agregando un NSPredicate
a NSFetchRequest
:
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary * bindings) {return([evaluatedObject isExpired]);}];
[fetchRequest setPredicate:predicate];
pero obtengo el error: *** Terminating app due to uncaught exception ''NSInvalidArgumentException'', reason: ''Problem with subpredicate BLOCKPREDICATE(0x272ac)'' ***
. ¿Esto significa que no puede usar un predicado de bloque con una NSFetchRequest? ¿O acabo de construirlo incorrectamente?
¡Gracias!
Entonces, parece que hemos establecido en los comentarios a la publicación original que esto es probablemente causado por las tiendas SQLite que son incompatibles con los predicados de bloque, ya que Core Data no puede traducirlos a SQL para ejecutarlos en la tienda (gracias, JoostK).
Puede haber un par de formas de superar esto:
- Siempre que la fecha de finalización de sus entidades sea un atributo regular, es posible que pueda expresar la restricción de vencimiento como una cadena de formato de predicado en lugar de un predicado de bloque, que Core Data debería poder traducir a una cláusula de SQL.
- Si lo anterior es posible, probablemente prefiera usar una plantilla de solicitud de recuperación para recuperar los artículos caducados. Sin embargo, necesitaría pasar una variable de sustitución como
$NOW
para dar acceso a la fecha actual. Esto tiene la ventaja de hacer aparecer la plantilla de predicado en el editor de modelos. - Ambos enfoques, sin embargo, tienen la desventaja de duplicar la funcionalidad existente (es decir, su método es
isExpired
). De modo que otra forma sería obtener primero todas las entidades cualificadoras, independientemente de su estado de caducidad, y luego ejecutar un paso de filtrado dedicado en el conjunto resultante de entidades para descartar las no caducadas. Dado que en ese punto, han sido completamente resucitados de la tienda, deberías poder usar un predicado de bloque para esto.
Puede hacer una solicitud de búsqueda normal sin especificar el predicado, y luego filtrar la matriz resultante:
NSArray *allEvents = [context executeFetchRequest:fetchRequest];
if (!allEvents) { // do error handling here
}
NSArray *expiredEvents = [allEvents filteredArrayUsingPredicate:predicate];