Search code examples
ioscore-datansfetchedresultscontroller

How to pass NSManagedObject to NSPredicate and how to save one-to-many Entities


I have a simple iOS8 Core Data application that lists information about a patient in a Master Detail structure. Xcode 6.3.1 That piece of the app works fine - a tableView of Patients with details on each Patient in a second view controller. Core Data has just two entities - Patient and Note and I set a one-to-many relationship. Each Patient can have many Notes, but each Note belongs to only one Patient.

Two Entities

On the Patient detail page I have a button that launches a second tableview-viewcontroller pair for the list of Notes and Note detail that belongs to that Patient.

Using a fetchedresultscontroller, the data is correctly populated in the Patient table view and the Patient Detail view. However, I can't seem to tie the Notes to an individual Patient. My attempts to retrieve notes belonging to an individual Patient have not worked either, but I suspect that is due to the fact that I haven't linked the Notes to a Patient object when saving the Note.

The Note save code:

func addNewNote() {

    makeEntryFieldsEnabledYES()

    //the Patient that owns this record is available as self.patientPassedIn
    //println("patientPassedIn is: \(patientPassedIn)")

    let context = kAppDelegate.managedObjectContext
    let entity = NSEntityDescription.entityForName("Note", inManagedObjectContext: kAppDelegate.managedObjectContext!)
    var noteToAdd = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: kAppDelegate.managedObjectContext!) as! Note

    noteToAdd.setValue(self.titleField.text, forKey: "title")
    noteToAdd.setValue(self.noteCategoryField.text, forKey: "noteCategory")
    noteToAdd.info = informationView.text
    noteToAdd.creationDate = NSDate()

    kAppDelegate.saveContext()

    performSegueWithIdentifier("unwindToNotesTableViewController", sender: self)

}//addNewNote

I do pass the relevant Patient object to the Note view controller, but I have not been able to link the note to that object.

How does one construct a save operation for a to-many entity so that the many Note objects relate only to the single Patient object? Then how do you construct the fetch request to fetch only the Note objects that belong to a given Patient? I want to pass a Patient object to the predicate and retrieve the appropriate notes.

The Note fetching code:

var fetchedResultsController: NSFetchedResultsController {

    managedObjectContext = kAppDelegate.managedObjectContext

    if myFetchedResultsController != nil {
        return myFetchedResultsController!
    }

    let fetchRequest = NSFetchRequest()

    // Check this: auto generate didn't work - fix that
    let entity = NSEntityDescription.entityForName("Note", inManagedObjectContext: managedObjectContext)

    fetchRequest.entity = entity
    fetchRequest.fetchBatchSize = 20

    let sortDescriptor = NSSortDescriptor(key: "creationDate", ascending: false)
    let sortDescriptors = [sortDescriptor]

    fetchRequest.sortDescriptors = [sortDescriptor]

    //prove that you have passed the Patient object
    var testString = passedInPatient?.lastName
    println(testString!)

    //try this for only retrieving the notes for the given patient
    //this does not work
    var notePredicate = NSPredicate(format: "passedInPatient")
    fetchRequest.predicate = notePredicate
    //
    //try above

    let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)

    var countError : NSError? = nil
    var count = managedObjectContext.countForFetchRequest(fetchRequest, error: &countError)
    println("The count is \(count)")

    aFetchedResultsController.delegate = self
    myFetchedResultsController = aFetchedResultsController

    var error: NSError? = nil
    if !myFetchedResultsController!.performFetch(&error) {
        //create an alert if the fetching fails
        println("Unresolved error \(error), \(error!.userInfo)")
        abort()
    }//if !

    return myFetchedResultsController!

}//var fetchedResultsController

I do pass the relevant Patient object to the Note view controller, but I have not been able to link the note to that object.

How does one construct a save operation for a to-many entity so that the many Note objects relate only to the single Patient object? Then how do you construct the fetch request to fetch only the Note objects that belong to a given Patient? I want to pass a Patient object to the predicate and retrieve the appropriate notes.


Solution

  • In your addNewNote function, add another line to set the relationship (it is easiest to set the to-one relationship; CoreData will automatically set the inverse relationship for you):

    noteToAdd.patient = patientPassedIn
    

    In your NSFetchedResultsController, the format you need for your predicate is like this:

    var notePredicate = NSPredicate(format: "patient == %@", passedInPatient)
    fetchRequest.predicate = notePredicate