10

I have a core data relationship where one entity holds many of another entity. As far as I am aware each instance of the many class is held inside an NSSet? inside the one class. (?)

My question is - what is the best way to add items to this set? I figure this must be a very common problem - but I cannot seem to find an easy method.

This is my attempt: (This is all taken from the one class)

static var timeSlotItems: NSSet? //The Set that holds the many?


...



static func saveTimeSlot(timeSlot: TimeSlot) { //TimeSlot is the many object
    retrieveValues()
    var timeSlotArray = Array(self.timeSlotItems!)
    timeSlotArray.append(timeSlot)
    var setTimeSlotItems = Set(timeSlotArray)
    self.timeSlotItems = setTimeSlotItems // This is the error line

}

Where retrieveValues() just updates all the coreData values in the class. TimeSlot is the many object which I want to add.

I get an error on the last line, the error is: "cannot invoke initializer for type Set<_> with an argument of list of type Array"

Am I conceptually wrong at all? Thanks!

Dale Baker
  • 329
  • 1
  • 3
  • 14

3 Answers3

15

For one-to-many this is easy. Just use the reverse to-one relationship.

timeSlot.item = self

For many-to-many I use this convenience method:

// Support adding to many-to-many relationships

extension NSManagedObject {
    func addObject(value: NSManagedObject, forKey key: String) {
        let items = self.mutableSetValueForKey(key)
        items.addObject(value)
    }

    func removeObject(value: NSManagedObject, forKey key: String) {
        let items = self.mutableSetValueForKey(key)
        items.removeObject(value)
    }
}

which is used like this:

self.addObject(slot, forKey:"timeSlotItems")
Mundi
  • 79,884
  • 17
  • 117
  • 140
15

Nowadays it is this easy...

For a to-many item named say "Reply", CoreData knows to add a call "addToReplys".

Hence...

p = one Post. your core data Post items have many core data Reply items.

for jr in yourJson {
    r = convert jr to a core data Reply
    
    p.addToReplys( r )

so it's just

p.addToReplys( r )

Full example

enter image description here

Community
  • 1
  • 1
Fattie
  • 27,874
  • 70
  • 431
  • 719
5

You've declared both timeSlotItems and saveTimeSlot: as static, so I'm not sure what your intention is there. I suspect it's not what you need.

In the same way that Core Data automatically runtime-generates optimized accessors for attributes, it also generates accessors for relations.

You don't say what the name of the "one" side of the to-many relation is, but if I assume that it's something like Schedule, where Schedule has a to-many relation to TimeSlot called timeSlotItems, then Core Data will runtime-generate the following accessors for you:

class Schedule: NSManagedObject {
    @NSManaged public var timeSlotItems: Set<TimeSlot>
    @NSManaged public func addTimeSlotItemsObject(value: TimeSlot)
    @NSManaged public func removeTimeSlotItemsObject(value: TimeSlot)
    @NSManaged public func addTimeSlotItems(values: Set<TimeSlot>)
    @NSManaged public func removeTimeSlotItems(values: Set<TimeSlot>)
}
Trevor Squires
  • 531
  • 4
  • 7
  • I made them both static because this class is essentially the class of global values used throughout the app - everything in that class is static - I should have clarified, sorry! – Dale Baker Dec 16 '15 at 23:16
  • @DaleBaker Global variables, global managed objects, a global managed object context... while you may think you need them, they're never a good solution, and they will lead to more problems than they "solve" for you. At some point, you'll desire to use a scratch context, or do something off the main thread, or mock, and find it difficult or impossible to test or encapsulate your code, because everything is needlessly tightly coupled. –  Dec 26 '15 at 13:33
  • @TrevorSquires Actually, I think that you can use the `insert` and `remove` methods of the `Set` directly. – FranMowinckel Jan 30 '16 at 18:40