Tuesday, February 28, 2017

Sort Descriptor based on ordered to-many relationship

Leave a Comment

Description of my core data model:

  • Project and Issues entities
  • Project has an ordered one-to-many relationship to Issues named issues
  • Issue has one-to-one relationship with Project named parentProject

Here is my code to obtain issues:

let fetchRequest = NSFetchRequest(entityName: "Issue")     fetchRequest.predicate = NSPredicate(format: "parentProject CONTAINS[cd] %@", argumentArray: [project])     fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]      let frc = NSFetchedResultsController(         fetchRequest: fetchRequest,         managedObjectContext: dataManager.context,         sectionNameKeyPath: nil,         cacheName: nil)      return arc 

Even though I have all issues from the project object, I prefer to obtain issues using fetched results controller, so they will always be updated and I like the integration with tables. I also like that in navigation controller screen before the projects are displayed using FRC as well.

As you see in the code the Issues are sorted by the name parameter.

However I'd like them to be sorted by the order I keep them in the NSMutableOrderedSet of project.

AFAIK I cannot use NSSortDescriptor with comparator/selector when it's used to Core Data.

Do you know how to do it? Thanks in advance.

3 Answers

Answers 1

If you use the relationship keypath (in your case parentProject) it will sort according to the ordered set. so you can use

fetchRequest.sortDescriptors = [NSSortDescriptor(key: "parentProject.name", ascending: true),NSSortDescriptor(key: "parentProject", ascending: true)] 

This will first sort them by project, then inside each project group it will be sorted by the same order as the ordered set in the relationship. Optionally you can put each issue's project in a different section by using sectionNameKeyPath.

If you don't use parentProject.name (or something like it - like parentProject.lastUpdated) first then they will ONLY be sorted according to the order of orderedSet. In other words it will be all of the first issues, then all of the second issues etc. This is probably not what you want.

Answers 2

This may be a kluge, but anyway. It seems to me your first fetch is a filter.. e.g. show me issues for this project. Maybe you could perform a second fetch, on the selected issues, and this time not filtering them, but sorting them?

Regarding CoreData, I have a sorted fetch like this:

  func fetchItem() {         print(#function)          let sortDescriptor: NSSortDescriptor!         let defaults: UserDefaults = UserDefaults.standard         if defaults.integer(forKey: "sequenceSwitchValue") == 0 {             sortDescriptor = NSSortDescriptor(key: "itemName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))         } else {             sortDescriptor = NSSortDescriptor(key: "itemName", ascending: false, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))         }          let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext         let request = NSFetchRequest<NSFetchRequestResult>(entityName: itemEntity)         request.sortDescriptors = [sortDescriptor]         let predicate: NSPredicate = NSPredicate(format: "itemName == %@", incomingItemName)         request.predicate = predicate           do {             items = try context.fetch(request) as! [ItemEntity]         } catch let error as NSError {             print("Error While Fetching Data From DB: \(error.userInfo)")         }          if items.count > 0 {             let currentItem = items[0] 

You may be able to work a relationship value into the predicate..

Answers 3

The simplest way to keep order is to add a property for the "issue" entity. Something called position of type Int. And use sort Descriptor that would sort entities by this position property

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment