2017-03-06 1 views
1

J'ai un NSFetchedResultsController qui alimente un UITableViewController avec Appointment entités qui ont, entre autres, une propriété dateTime.Trier sur (avant ou après aujourd'hui) dans NSSortDescriptor

Mon but est d'avoir une liste de rendez-vous triées comme ceci:

  1. Aujourd'hui
  2. Demain
  3. jour après-demain
  4. Hier
  5. Avant-hier,

En d'autres termes: Premier sor t sur si c'est avant ou après aujourd'hui, puis sur dateTime. Donc d'abord trier (dateTime > %TODAY%), puis sur dateTime lui-même (futur ascendant, passé descendant).

Y at-il un moyen de le faire? Mon problème est que je ne peux pas utiliser% TODAY% dans un descripteur de tri, mais il existe peut-être un autre moyen d'obtenir le même résultat visuel.

MISE À JOUR: Sachez que la réponse acceptée n'est pas possible avec un NSFetchedResultsController. J'ai choisi une autre solution, en ordonnant le Appointments avant d'afficher la vue., En enregistrant cela dans la base de données, et laissez le NSFetchedResultsController prendre les changements.

MISE À JOUR 2: Réponse acceptée a fait pour faire exactement ce que je voulais. Ma mise en œuvre:

let futureAppointments = appointments.filter({ $0.dateTime != nil && $0.dateTime?.compare(Date()) == .orderedDescending }) 
    .sorted(by: { $0.dateTime?.compare($1.dateTime! as Date) == .orderedAscending }) 

let pastAppointments = appointments.filter({ $0.dateTime != nil && $0.dateTime?.compare(Date()) == .orderedAscending }) 
    .sorted(by: { $0.dateTime?.compare($1.dateTime! as Date) == .orderedDescending }) 

let sorted = futureAppointments + pastAppointments 

for (index, appointment) in sorted.enumerated() { 
    appointment.order = NSNumber(integerLiteral: index) 
} 

Répondre

0

C'est seulement une idée. Peut-être que vous pouvez créer SortDescriptor comme ceci:

NSSortDescriptor(key: "test", ascending: true) { (v1, v2) -> ComparisonResult in 
     guard let d1 = v1 as? Date else 
     { 
      return .orderedAscending 
     } 
     guard let d2 = v2 as? Date else 
     { 
     return .orderedAscending 
     } 
     if abs(d1.timeIntervalSinceNow) < abs(d2.timeIntervalSinceNow) { return .orderedAscending } 
     if abs(d1.timeIntervalSinceNow) > abs(d2.timeIntervalSinceNow) { return .orderedDescending } 
     return .orderedSame 
} 

Je pense que ce sera le travail.

+0

Vous ne pouvez pas utiliser un descripteur de tri basé sur un bloc dans une requête fetchRequest. voir https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/PersistentStoreFeatures.html#//apple_ref/doc/uid/TP40001075-CH23-SW1 –

+0

Comme Jon l'a dit, je ne peux pas utiliser cela, mais cela m'a fait penser à une autre solution, en ordonnant avec votre descripteur de tri avant la récupération. Maintenant j'ai une propriété 'order' qui est définie chaque fois que quelqu'un ouvre la vue. Il n'y a jamais plus de 10 rendez-vous, donc je ne vois pas de problèmes de performance. Merci – Arjan

+0

@Sergey FYI votre réponse n'a pas fait exactement ce que je voulais (j'ai fait la question plus claire). J'ai fait ma propre implémentation mais si vous le souhaitez, vous pouvez mettre à jour votre réponse. – Arjan

1

Utilisez deux fetchedResultsControllers, un classement ascendant avec un prédicat excluant ceux créés avant aujourd'hui, et un classement descendant avec un prédicat hors rendez-vous à venir.

Ecrivez une fonction à convertir entre le chemin d'index fetchedResultsController et le chemin d'index de tableview et vice versa. Assurez-vous de suivre le type d'indexPath avec lequel vous traitez et ce n'est pas si difficile.

+0

Salut Jon, J'ai en fait une classe de base 'CoreDataTableViewController' que je ne voulais pas changer ou copier pour un écran, donc je suis allé avec une autre solution. Merci d'avoir réfléchi. – Arjan