Estoy buscando entidades de Core Data en SwiftUI y me gustaría ordenarlas así:
- Si hay una próxima fecha, ordénelas ascendentes
- Debajo de los que tienen una próxima fecha, ordene el resto por fecha de creación
Tengo:
@FetchRequest(entity: MyEntity.entity(), sortDescriptors: [
NSSortDescriptor(keyPath: \MyEntity.nextDate, ascending: true),
NSSortDescriptor(keyPath: \MyEntity.dateCreated, ascending: true)
]) private var entities: FetchedResults<MyEntity>
El problema es que aquellos que no tienen una próxima fecha se ordenan por encima de aquellos que no tienen una próxima fecha, como se ve en este otro pregunta.
Traté de subclasificar NSSortDescriptor
para mover los valores nil
hasta el final, pero nunca llama a ninguna de las funciones anuladas.
final class NilsLastSortDescriptor: NSSortDescriptor {
override func copy(with zone: NSZone? = nil) -> Any {
return NilsLastSortDescriptor(key: self.key, ascending: self.ascending, selector: self.selector)
}
override var reversedSortDescriptor: Any {
return NilsLastSortDescriptor(key: self.key, ascending: !self.ascending, selector: self.selector)
}
override func compare(_ object1: Any, to object2: Any) -> ComparisonResult {
if (object1 as AnyObject).value(forKey: self.key!) == nil && (object2 as AnyObject).value(forKey: self.key!) == nil {
return .orderedSame
}
if (object1 as AnyObject).value(forKey: self.key!) == nil {
return .orderedDescending
}
if (object2 as AnyObject).value(forKey: self.key!) == nil {
return .orderedAscending
}
return super.compare(object1, to: object2)
}
}
También intenté usar la API NSSortDescriptor
que incluye un bloque de comparación, sin embargo, esto falla
Excepción: "NSSortDescriptor no compatible (no se admiten bloques de comparación)"
¿Cómo podría lograr el comportamiento de clasificación deseado?
2 respuestas
@FetchRequest usa el descriptor de ordenación como parte de una solicitud de búsqueda, y en consecuencia no puede usar bloques de comparación en la definición de la solicitud de búsqueda (al menos, no con un almacén SQLite). Sin embargo, puede ordenar los resultados de la búsqueda (entities
) como parte del procesamiento de body
de la vista, utilizando sorted (by :):
var body: some View {
VStack {
List{
ForEach(self.entities.sorted(by: { first, second in
if first.nextDate == nil && second.nextDate == nil { return (first.dateCreated <= second.dateCreated) }
if first.nextDate == nil { return false }
if second.nextDate == nil { return true }
if first.nextDate! == second.nextDate! { return (first.dateCreated <= second.dateCreated) }
return (first.nextDate! < second.nextDate!)
}), id: \.self) { myEntity in
// Your code for your cells...
...
}
}
}
}
Supuse por simplicidad que dateCreated
no es opcional. De lo contrario, deberá modificar el predicado para que la ordenación maneje los valores nulos. Probablemente también podría escribirse con más precisión, pero espero que entiendas la idea.
Solo para tener en cuenta que se está ordenando en la memoria, por lo que no tengo idea del rendimiento y / o impacto de la memoria de esta solución.
En CoreData, la ordenación solo usa un método de la clase NSString como "compare:" o "localizedStandardCompare:" algo así.
Como no puede anular esos métodos o incluso cambiarlos en la mayoría de los casos, puede considerar otras soluciones.
En lugar de la fecha "Cero", puede establecer un Special Date
que es muy tarde si los datos deseados son 'Cero'. De esta manera, puede ordenar esas fechas en la parte inferior. No puede mostrar esas fechas especiales, o mostrarlas como "Cero" en SwiftView.
Puedes jugar al juego NSString
, no al subclass
Nuevas preguntas
ios
iOS es el sistema operativo móvil que se ejecuta en el iPhone, iPod touch y iPad de Apple. Use esta etiqueta [ios] para preguntas relacionadas con la programación en la plataforma iOS. Use las etiquetas relacionadas [Objective-C] y [Swift] para problemas específicos de esos lenguajes de programación.