-1

I have a very similar question to: Swift: Store arrays of custom classes in Core Data

The difference is that question was looking to add to a custom class array in Core Data one element at a time. I am looking to add the entire array at once. When I try to, I get the following error: [CDTester.MassOfSubpart entity]: unrecognized selector sent to instance.

I made a simple app to demonstrate the error and hopefully figure out where I am going wrong. I uploaded it to GitHub here: https://github.com/Yrban/Core-Data-Test-App

The code where it crashes is here:

func saveWidget(){
    print("saveWidget() entered")
    if self.massOfSubpartMeasurementDict.count > 0,
        self.massOfSubpartMeasurementDict.count == self.numberOfSubparts,
        self.manufacturer != "",
        self.title != "" {

        var massPerSubpartMeasurementArray: [MassOfSubpart]
        massPerSubpartMeasurementArray = massOfSubpartMeasurementDict.map {
            return MassOfSubpart(subpart: $0.key, mass: Measurement(value: Double($0.value)!, unit: self.massUnit))
        }
        let massOfSubpartSet = Set(massPerSubpartMeasurementArray)

        let widget = Widget(context: self.managedObjectContext)
        widget.id = UUID()
        widget.madeBy?.name = self.manufacturer
        widget.hasMassOfPart = massOfSubpartSet // FIXME: The crash is here
        widget.title = self.title

        do {
            print("SaveWidget() attempted/n")
            try self.managedObjectContext.save()
        } catch {
            print("SaveWidget() failed/n")
            // handle the Core Data error
            // Show alert as to status
        }
    }
}

My Core Data model is:

Core Data Model

MassOfSubpart is a custom object:

import SwiftUI

public class MassOfSubpart: NSObject, Codable {

    var subPart: Int
    var mass: Measurement<UnitMass>

    override init() {
        self.subPart = 1
        self.mass = Measurement(value: 0.0, unit: UnitMass.grams)
    }

    init(subpart: Int, mass: Measurement<UnitMass>){
        self.subPart = subpart
        self.mass = mass
    }
}

I have read everything I could find, including Apple's documentation. I feel I am close, but I am obviously missing something important. Any help would be appreciated.

Yrb
  • 8,103
  • 2
  • 14
  • 44
  • Have you set breakpoints in your `saveWidget` function? Assume it is the call to `massOfSubpartMeasurementDict.map {}` that causes the error? Have you attempted to iterate through the `massOfSubpartMeasurementDict` using [other methods of iteration](https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html) such as `for...in` - sometimes that helps identify an issue? Also, have you tried casting your array to NSSet before you attempt to set `widget.addToHasMassOfPart ` (maybe use a guard statement)? – andrewbuilder Jan 09 '20 at 23:33
  • I did set breakpoints and set a comment in the code as to what is causing the crash. It is: widget.addToHasMassOfPart(Set(massPerSubpartMeasurementArray) as NSSet). I did try it casting it as an NSSet prior as well. Actually my test code is now that way. Nothing changed. I hadn't considered a guard statement, but the values look correct when inspected at the break point. I am pretty sure I have a Set of MassOfSubpart going in to the MOC. – Yrb Jan 10 '20 at 02:03
  • I am going to update this question as I have tried a few more things, but I still have the same crash. – Yrb Jan 10 '20 at 02:08
  • I have updated the GitHub and the saveWidget function. From everything I can determine, Core Data does not like MassOfSubpart. I am thinking that maybe MassOfPartEntity can't handle MassOfSubpart. I am going to look into that. You can see the entire Core Data structure on GitHub. – Yrb Jan 10 '20 at 02:58
  • `Set` is different to `NSSet`. it is possible you have a type mismatch. Core Data seems to me to be very particular when it comes to `Set` and `NSSet`. Are you manually creating your `NSManagedObject` subclasses? If so, please show your `NSManagedObject` subclass for `Widget`. If not you will have to create an `NSSet`. – andrewbuilder Jan 10 '20 at 04:04
  • I thought of that and have tried it both ways. It didn't change the error. – Yrb Jan 10 '20 at 18:11

1 Answers1

0

I finally figured out my error. I have not used relationships before, so it didn't dawn on me what I was doing. When I was accessing MassOfPartEntity through its relationship with Widget, I was sending a Set, my custom object through. However, I had to send a Set, the actual entity through. Therefore, I changed saveWidget to this:

func saveWidget(){
    print("saveWidget() entered")
    if self.massOfSubpartMeasurementDict.count > 0,
        self.massOfSubpartMeasurementDict.count == self.numberOfSubparts,
        self.manufacturer != "",
        self.title != "" {

        let massOfPartEntity = MassOfPartEntity(context: self.managedObjectContext)
        var massPerSubpartEntityArray: [MassOfPartEntity]
        massPerSubpartEntityArray = massOfSubpartMeasurementDict.map {
            massOfPartEntity.subPart = Int16($0.key)
            if let massDouble = Double($0.value) {
                massOfPartEntity.mass = Measurement(value: massDouble, unit: massUnit)
            } else {
                massOfPartEntity.mass = Measurement(value: 0.0, unit: massUnit)
            }
            return massOfPartEntity
        }
        let massOfSubpartSet = Set(massPerSubpartEntityArray) as NSSet

        let widget = Widget(context: self.managedObjectContext)
        widget.id = UUID()
        widget.madeBy?.name = self.manufacturer
        widget.addToHasMassOfPart(massOfSubpartSet) // FIXME: The crash is here
        widget.title = self.title

        do {
            print("SaveWidget() attempted/n")
            try self.managedObjectContext.save()
        } catch {
            print("SaveWidget() failed/n")
            // handle the Core Data error
            // Show alert as to status
        }
    }
}

changing the Map function return so that it returned MassOfPartEntity's that eventually became a Set. Essentially, it was a type mismatch.

Thanks to those who responded as talking it out definitely helped resolve this.

Yrb
  • 8,103
  • 2
  • 14
  • 44