Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CoreData One-To-Many, sorting the many

Tags:

I have a small app that I'm working on to learn CoreData. These are the entities for CoreData.

extension Person {

    @NSManaged var firstName: String?
    @NSManaged var lastName: String?
    @NSManaged var age: NSNumber?
    @NSManaged var personToBook: NSSet?

}

extension Books {

    @NSManaged var bookName: String?
    @NSManaged var bookISBN: String?
    @NSManaged var bookToPerson: Person?

}

The app is a list of people. Belonging to each person in the list can be one more more books.

I am easily able to sort the people.

    let fetchRequest = NSFetchRequest(entityName: "Person")
    let fetchSort = NSSortDescriptor(key: "lastName", ascending: true)
    fetchRequest.sortDescriptors = [fetchSort]

    fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
    fetchedResultsController.delegate = self

    do {
        try fetchedResultsController.performFetch()
    }
    catch let error as NSError {
        print("Unable to perform fetch: \(error.localizedDescription)")
    }

What I am having a tough time working out is how to sort the Books in alphabetical order, like I am the people. When I tap on a person in the people list, I segue to a UITableView that contains a list of books. In the prepareForSegue, I pass in the selected person, the context, and the NSFetchedResultsController that I am using in the person list.

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let vc = segue.destinationViewController as! BooksController

    vc.person = fetchedResultsController.objectAtIndexPath(selectedIndex) as! Person
    vc.context = self.context
    vc.fetchedResultsController = self.fetchedResultsController
}

The UITableView is populated by person.personToBook.

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return (person.personToBook?.count)!
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("BooksCell", forIndexPath: indexPath)
    let book = person.personToBook?.allObjects[indexPath.row] as! Books

    cell.textLabel?.text = book.bookName!

    return cell
}

Books are added to the correct person in this manner:

            let entity = NSEntityDescription.entityForName("Books", inManagedObjectContext: self.context)
            let bookInstance = Books(entity:entity!, insertIntoManagedObjectContext: self.context)

            bookInstance.bookName = alertController.textFields?[0].text
            bookInstance.bookISBN = alertController.textFields?[1].text

            self.person.mutableSetValueForKey("personToBook").addObject(bookInstance)

            do {
                try self.context.save()
                self.tableView.reloadData()
            }
            catch let error as NSError {
                print("Error saving a book \(error.localizedDescription)")
            }

personToBook is an NSSet, and this is not sorted. I thought about using another NSFetchedResultsController to pull the list of books out, but there is nothing unique that is identifying the books as belonging to a specific user. For instance, I could have two people with the same name of John Doe. Because of this, I'd have no way to set theNSPredicate` so that it would only pull in books for one of the John Does.

One though that I had is that I could add some sort of UniqueID to the Person entity, like I'd do in SQL. This would ensure that I could get the Books records for only the correct person. I've been told that I should not do this in CoreData. That leads me to believe that there must be some way to sort the items in the to-many part of this.

What are the ways that I can sort my Books data?