squarehippo10
squarehippo10

Reputation: 1945

Swift CoreData saving a one-to-one relationship

Below I have a handful of segmented controls that I'm trying to save using CoreData. It seems pretty straight forward, but only the most recent control index is being saved. The rest are being reset to 0 for some reason. I have unchecked the default setting for each attribute.

Quote is my main entity and has a one-to-one relationship with Worksheet called worksheet.

@IBAction func segmentPressed(_ sender: UISegmentedControl) {
   let worksheet = Worksheet(context: context)

   switch sender.tag {
   case 0:
      worksheet.irrigation = Int32(irrigationSegment.selectedSegmentIndex)
   case 1:
      worksheet.waste = Int32(wasteSegment.selectedSegmentIndex)
   case 2:
      worksheet.water = Int32(waterSegment.selectedSegmentIndex)
   default:
      break
   }

   if let quote = currentQuote as? Quote {
      quote.worksheet = worksheet
      appD.saveContext()
   }
 }

UPDATE: It occurred to me to get rid of the switch statement altogether...and now it saves properly. But I'd still like to know why the values were being reset. Maybe an Int attribute automatically gets set to zero when its context is saved but it has no value? It seems like that's what the default value setting would do. Except mine were all unchecked.

Upvotes: 1

Views: 623

Answers (1)

pbasdf
pbasdf

Reputation: 21536

Every time the segmentPressed function is executed, a new Worksheet object is created (with default values for all its attributes). Your code as written (with the switch statement) sets the value for only one attribute, depending on which segmented control has been tapped. As you note with your update, after removing the switch statement, your code updates the values for all the attributes, and all appears good.

However, since you are creating a new Worksheet object each time, you need to consider what's happening to the old ones. As the relationship is one-one, when you assign your new Worksheet to the currentQuote, the link to the old Worksheet object is removed - but the old Worksheet object remains. You are therefore building up a group of "orphaned" Worksheet objects which have no link to any Quotes.

To avoid this, you should check whether the currentQuote has an existing Worksheet object. If so, update the appropriate attribute of that object; if not, create a new Worksheet, set its attribute values (you might want to set all of them) and set the relationship to the currentQuote. Something like this:

@IBAction func segmentPressed(_ sender: UISegmentedControl) {
    if let worksheet = currentQuote?.worksheet {
        switch sender.tag {
            case 0:
                worksheet.irrigation = Int32(irrigationSegment.selectedSegmentIndex)
            case 1:
                worksheet.waste = Int32(wasteSegment.selectedSegmentIndex)
            case 2:
                worksheet.water = Int32(waterSegment.selectedSegmentIndex)
            default:
                break
        }
        appD.saveContext()
    } else {
        if let quote = currentQuote as? Quote {
            let worksheet = Worksheet(context: context)
            worksheet.irrigation = Int32(irrigationSegment.selectedSegmentIndex)
            worksheet.waste = Int32(wasteSegment.selectedSegmentIndex)
            worksheet.water = Int32(waterSegment.selectedSegmentIndex)
            quote.worksheet = worksheet
            appD.saveContext()
        }
    }
}

Upvotes: 1

Related Questions