How to assign CoreData many-to-many relationship in Swift?

11,380

Solution 1

As of Xcode 7 and Swift 2.0, the release note 17583057 states:

The NSManaged attribute can be used with methods as well as properties, for access to Core Data’s automatically generated Key-Value-Coding-compliant to-many accessors.

@NSManaged var employees: NSSet

@NSManaged func addEmployeesObject(employee: Employee)
@NSManaged func removeEmployeesObject(employee: Employee)
@NSManaged func addEmployees(employees: NSSet)
@NSManaged func removeEmployees(employees: NSSet)

These can be declared in your NSManagedObject subclass. (17583057)

So you just have to declare the following methods and CoreData will take care of the rest:

@NSManaged func addDogBreedsObject(dogBreed: DogBreed)
@NSManaged func removeDogBreedsObject(dogBreed: DogBreed)
@NSManaged func addDogBreeds(dogBreeds: NSSet)
@NSManaged func removeDogBreeds(dogBreeds: NSSet)

Solution 2

Swift cannot generate dynamic runtime accessors due to strict type system. You can create an extension to Disease class and add missed methods manually, here is the code:

extension Disease {
    func addDogBreedObject(value:DogBreed) {
        var items = self.mutableSetValueForKey("dogBreed");
        items.addObject(value)
    }

    func removeDogBreedObject(value:DogBreed) {
        var items = self.mutableSetValueForKey("dogBreed");
        items.removeObject(value)
    }
}

Remarks:

I suggest you to create separate file for extension Disease+CoreData.swift, This should help to keep your code from overrides when you re-generate the CoreData model.

It is sufficient to create relationship in one of managed objects, second one will be updated with back reference. (Same as was with Objective-C)

Important: To make it all work you should verify that class names of entities in you CoreData model includes your module name. E.g. MyProjectName.Disease

Answer inspired by: Setting an NSManagedObject relationship in Swift

Solution 3

If you are looking for a simple approach just use this.

import CoreData
extension NSManagedObject {
    func addObject(value: NSManagedObject, forKey: String) {
        var items = self.mutableSetValueForKey(forKey);
        items.addObject(value)
    }
}

The implementation:

department.addObject(section, forKey: "employees")

Instead of writing the same method on every NSManageObject class that needs it.

Solution 4

Actually you can just write:

@NSManaged var dogBreed: Set<DogBreed>

And use the insert and remove methods of the Set directly.

Solution 5

As an extension to @Naz. And in combination with @Ash's comment. I've found the only working solution for xCode 6.3.1

import CoreData

extension NSManagedObject {
    func addObject(value: NSManagedObject, forKey: String) {
        self.willChangeValueForKey(forKey, withSetMutation: NSKeyValueSetMutationKind.UnionSetMutation, usingObjects: NSSet(object: value) as Set<NSObject>)
        var items = self.mutableSetValueForKey(forKey);
        items.addObject(value)
        self.didChangeValueForKey(forKey, withSetMutation: NSKeyValueSetMutationKind.UnionSetMutation, usingObjects: NSSet(object: value) as Set<NSObject>)
    }
}

You have to call the willChange and didChange handlers in order to correctly add an object to a to-many relationship in Swift.

myManagedObject.addObject(value, forKey: "yourKey")
Share:
11,380

Related videos on Youtube

tadasz
Author by

tadasz

Updated on September 15, 2022

Comments

  • tadasz
    tadasz over 1 year

    I have a NSManagedObject class

    class Disease: NSManagedObject {
        @NSManaged var diseaseId: String
        @NSManaged var diseaseName: String
        @NSManaged var dogBreed: NSSet
    }
    

    How do I add a new relationship to dogBreed? If i change var type to NSMutableSet, the changes are not saved to database. Any ideas?

  • Ash
    Ash about 9 years
    I found that this code would not work for my app without wrapping the setting process in the proper key value observation code, to whit self.willChangeValueForKey("key", withSetMutation:<set mutation type>, usingObjects:<objects changed>) and the corresponding didChangeValueForKey method. Without this all kinds of strange and apparently unrelated errors were reported.
  • Keenle
    Keenle about 9 years
    Good point. I'll test your suggestion and add to the answer when back to my dev desktop.
  • Ali Beadle
    Ali Beadle about 9 years
    Ah ha - I like this solution. Neat.
  • Ben Guild
    Ben Guild almost 8 years
    I can't believe this is still a bug. Maybe in a week or so they'll fix it at WWDC.