WWDC21 SALE: Save 50% on all my Swift books and bundles! >>

SOLVED: Codable in Core Data with to many relationships

Forums > Swift

I've been able to find multiple articles about codable in core data and decoding JSON. But I'm struggling when a to-many relationship exists. I currently have the following which works, but how do I filter the JSON based on an attribute in the child?

Checklist entity (Checklist <--->> TestGroup, relationship called hasTestGroups)

required convenience public init(from decoder: Decoder) throws {
    guard let contextUserInfoKey = CodingUserInfoKey.context,
      let managedObjectContext = decoder.userInfo[contextUserInfoKey] as? NSManagedObjectContext,
      let entity = NSEntityDescription.entity(forEntityName: "Checklist", in: managedObjectContext) else {fatalError("Failed to decode Checklist")}

    self.init(entity: entity, insertInto: managedObjectContext)
    let values = try decoder.container(keyedBy: CodingKeys.self)
    do {
      name = try values.decode(String?.self, forKey: .name)
      hasTestGroups = NSSet(array: try values.decode([TestGroup].self, forKey: .hasTestGroups))
    } catch {
      print("decoding error")
    }
  }

Then in a view where I decode the JSON:

guard let url = Bundle.main.url(forResource: "masterdatabase", withExtension: "json") else {fatalError("no file")}
                do {
                  let json = try Data(contentsOf: url)
                  let decoder = JSONDecoder()
                  decoder.userInfo[CodingUserInfoKey.context!] = self.moc
                  do {
                    let subjects = try decoder.decode([Checklist].self, from: json)
                    subjects.first?.name = self.desiredChecklistName
                    subjects.first?.eventNumber = Int32(self.desiredChecklistNumber)!
                    subjects.first?.eventDate = self.desiredChecklistData

How do I filter the JSON on decode based on something like TestGroup.name? It's a NSSet, so .filter{$0...} doesn't work.

   

How does the model class look like? Even though Xcode generates relationships as NSSet you can easily change that to Set and it will work just fine.

   

Adding to the previous reply... You cant use NSSet like an array. What you can do though is to access the NSSet as an array by doing the following -

Go to your xcdatamodel and select the entity. Go to the attribute panel of the entity and change the Codgen attribute from Class definition to Manual/None Select Editor then Create NSManagedOject Subclass - Click Next, then make sure your entity is selected then click next. Make sure the yellow folder for your project is selected from the Group drop down then click Create. This will create the NSManaged Object files for your entity. Select the file which contains properties (attributes) for your entity and there you will see your attributes and relationships you have set for your entity. Below them add the following code -

public var nameArray: [PutTheNameOfTheEntityWhichThisEntityIsrRelatedToHere] {
        let set = nameOfTheNSSetInThisEntity as? Set<PutTheNameOfTheEntityWhichThisEntityIsrRelatedToHere> ?? []

        return set.sorted {
            // Put the sorting method you want here
            // For example if the entity has an attribute called title then you would put this
            $0.title < $1.title
            // This will sort the array based on its title 
        }
    }

Once you do this you can access this array in code EntityName.nameArray. Hope this helps

   

Sorry, just realised that this will not work when you want your entity to conform to Codable. There has been a couple of forum posts about this and we have not been able to find a way to get NSSet to conform to Codable. Im atill hunting for a way but have been unabke to find it.

   

Thanks everyone! Worked like a charm!

   

Save money with our WWDC sale!

SAVE 50% To celebrate WWDC21, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.