Search code examples
swiftcore-dataone-to-manynsfetchedresultscontrollerrelationships

CoreData - One-to-many relationship


I'll post the following code then explain my struggle

This function saves a day (like sunday, monday, tuesday, etc):

func appendDaysToArray() {
        let dayLabel = dayName.text
        daysArray.append(dayLabel)

        let dayEntity = NSEntityDescription.entityForName("TrainingDay", inManagedObjectContext: moc!)
        let trainingday = TrainingDay(entity: dayEntity!, insertIntoManagedObjectContext: moc)
        trainingday.day = dayName.text

        var error: NSError?
        moc?.save(&error)

        if let err = error {
            var status = err.localizedFailureReason
            println("\(status)")
        } else {
            println("Day #\(dayName.text) saved successfully!")
        }
    }

and this one saves details as a name, a number of sets and a number of repetitions (like gym exercises):

func appendTrainingDetails () {

        let nameLabel = exerciseName.text
        namesArray.append(nameLabel)
        let numberOfSets = setsNumber.text?.toInt()
        setsArray.append(numberOfSets!)
        let numberOfReps = repsNumber.text?.toInt()
        repsArray.append(numberOfReps!)

        let detailsEntity = NSEntityDescription.entityForName("TrainingDetails", inManagedObjectContext: moc!)
        let trainingdetails = TrainingDetails(entity: detailsEntity!, insertIntoManagedObjectContext: moc)
        trainingdetails.exerciseName = exerciseName.text
        trainingdetails.setsNumber = setsNumber.text!
        trainingdetails.repsNumber = repsNumber.text!


        var error: NSError?
        moc?.save(&error)

        if let err = error {
            var status = err.localizedFailureReason
            println("\(status)")
        } else {
            println("Exercise: #\(exerciseName.text) saved successfully!")
            println("Number of sets: #\(setsNumber.text) saved successfully!")
            println("Number of reps: #\(repsNumber.text) saved successfully!")
        }
    }

My app is working ok, but what I actually need is this: for each DAY, I will have multiple exerciseNames, setsNumber and repsNumber. I set a one-to-many relationship, but I don't know how to attribute the TrainingDetails to each day in the daysArray.

Here are my 2 models:

import Foundation
import CoreData

class TrainingDay: NSManagedObject {

    @NSManaged var day: String
    @NSManaged var relationship1: NSSet

}

and

import Foundation
import CoreData

class TrainingDetails: NSManagedObject {

    @NSManaged var exerciseName: String
    @NSManaged var repsNumber: String
    @NSManaged var setsNumber: String
    @NSManaged var relationship2: TrainingDay

}

Later, I'll have a button for each day and, when pressed, they will update a tableView with the list of exercises for that specific day. That's why I need to set this one-to-many relationship.

How can I achieve this?

Sorry for any mistakes. Thanks in advance!!


Solution

  • The documentation for what you want to do is in this link, under the heading "To-Many Relationships".

    Here is a short example. First, I recommend changing the names of your relationships to something more intuitive. It will really help:

    class TrainingDay: NSManagedObject {
        @NSManaged var day: String
        @NSManaged var trainingDetails: NSSet
    }
    
    class TrainingDetails: NSManagedObject {
        // ... other stuff here
        @NSManaged var trainingDay: TrainingDay
    }
    

    Make sure any changes you make to the code are also made in the model graph. Make sure that the relationships are configured to be the inverse of each other in the model graph.

    You can set the TrainingDay for a given TrainingDetails like this:

    // This assumes you've created a TrainingDay called "trainingDay1", and a 
    // TrainingDetails object called "details".
    details.trainingDay = trainingDay1
    

    Core Data takes care of creating the inverse relationship as well, so the trainingDay1 object will automatically add details to its trainingDetails set.

    If you are trying to add objects to the trainingDetails set in TrainingDay, you need to use the mutableSetValueForKey: method described in the documentation that I linked to. Basically, it looks like this:

    var details = trainingDay1.mutableSetValueForKey("trainingDetails")
    details.addObject(newTrainingDetails)
    

    The mutableSetValueForKey: creates a proxy object. Any changes made to the set that it returns are effective on the set you are trying to modify.

    Hope this helps!