How to define CoreData relationship in Swift?

匿名 (未验证) 提交于 2019-12-03 01:15:01

问题:

In CoreData, I have defined an unordered to-many relationship from Node to Tag. I've created an Swift entity like this:

import CoreData class Node : NSManagedObject {     @NSManaged var tags : Array } 

Now I want to add a Tag to an instance of Node, like this:

var node = NSEntityDescription.insertNewObjectForEntityForName("Node", inManagedObjectContext: managedObjectContext) as Node node.tags.append(tag) 

However, this fails with the following error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for to-many relationship: property = "tags"; desired type = NSSet; given type = _TtCSs22ContiguousArrayStorage000000000B3440D4; value = ( "<_ttc8motornav3tag:> (entity: Tag; id: 0xb343800 ; data: {...})" ).'

What is the correct type for to-many relationships?

回答1:

To be able to work with one-to-many relationship in Swift you need to define property as:

class Node: NSManagedObject {     @NSManaged var tags: NSSet } 

If you try to use NSMutableSet changes will not be saved in CoreData. And of course it is recommended to define reverse link in Node:

class Tag: NSManagedObject {     @NSManaged var node: Node } 

But still Swift cannot generate dynamic accessors in runtime, so we need to define them manually. It is very convenient to define them in class extension and put in Entity+CoreData.swift file. Bellow is content of Node+CoreData.swift file:

extension Node {     func addTagObject(value:Tag) {         var items = self.mutableSetValueForKey("tags");         items.addObject(value)     }      func removeTagObject(value:Tag) {         var items = self.mutableSetValueForKey("tags");         items.removeObject(value)     } } 

Usage:

// somewhere before created/fetched node and tag entities node.addTagObject(tag) 

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.Node



回答2:

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 addTagsObject(tag: Tag) @NSManaged func removeTagsObject(tag: Tag) @NSManaged func addTags(tags: NSSet) @NSManaged func removeTags(tags: NSSet) 


回答3:

Actually you can just define:

@NSManaged var employees: Set

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



回答4:

Building on @Keenle's answer, if you want to be cheeky and concise and be able to say

node.tags.append(tag) 

one can wrap the call to self.mutableSetValueForKey:

class Node: NSManagedObject {      var tags: NSMutableOrderedSet {         return self.mutableOrderedSetValueForKey("tags")     } } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!