在Swift中设置一个NSManagedObject关系
在Swift的NSManagedObject
子类中,如何将对象添加到关系属性中?
在Objective-C中,当从数据模型生成Xcode中的NSManagedObject
子类时,会自动生成类扩展,其中包含如下声明:
@interface MyManagedObject (CoreDataGeneratedAccessors) - (void)addMySubObject: (MyRelationshipObject *)value; - (void)addMySubObjects: (NSSet *)values; @end
但是,Xcode目前缺lessSwift类的这个类生成能力。
如果我尝试直接在Swift对象上调用等价的方法:
myObject.addSubObject(subObject)
…我在方法调用中遇到编译器错误,因为这些生成的访问器不可见。
我已经将关系属性声明为@NSManaged
,如文档中所述。
还是必须恢复到具有关系的数据模型的Objective-C对象?
是的,这是行不通的,Swift不能在运行时以这种方式生成访问器,它会打破types系统。
你必须做的是使用关键path:
var manyRelation = myObject.valueForKeyPath("subObjects") as NSMutableSet manyRelation.addObject(subObject) /* (Not tested) */
从Xcode 7和Swift 2.0开始(请参阅发行说明#17583057 ),只需将以下定义添加到生成的扩展文件即可:
extension PersonModel { // This is what got generated by core data @NSManaged var name: String? @NSManaged var hairColor: NSNumber? @NSManaged var parents: NSSet? // This is what I manually added @NSManaged func addParentsObject(value:ParentModel) @NSManaged func removeParentsObject(value:ParentModel) @NSManaged func addParents(value:Set<ParentModel>) @NSManaged func removeParents(value:Set<ParentModel>) }
这是因为
NSManaged属性可以与方法和属性一起使用,以访问Core Data自动生成的Key-Value-Coding兼容的多对多访问器。
添加此定义将允许您将项目添加到您的集合。 不知道为什么这些不是自动生成的…
Objective C中的核心数据自动创buildsetter方法( 1 ):
默认情况下,Core Data为受pipe对象类的build模属性(属性和关系)dynamic创build高效的公共和原始get和set访问器方法。 这包括键值编码可变代理方法,如addObject:和removed :,如在mutableSetValueForKey的文档中详细描述的: – pipe理对象对于所有的一对多关系都是有效的可变代理。
就像Xcode6-Beta2中的Swift一样,你必须自己实现这些访问器。 例如,如果你有一个无序的一对多的关系,从Way
到Node
,你addNodesObject
像这样实现addNodesObject
:
class Way : NSManagedObject { @NSManaged var nodes : NSSet func addNodesObject(value: Node) { self.mutableSetValueForKey("nodes").addObject(value) } }
这里的关键是你必须使用mutableSetValueForKey
/ mutableOrderedSetValueForKey
/ mutableArrayValueForKey
。 在这些集合/数组上,你可以调用addObject,它们将被存储在下一次刷新。
在NSMutableSet之上扩展解决scheme是NSMutableSet,因此这允许您直接添加或删除Person NSManagedObject到angular色,在这种情况下,Person有一个angular色,angular色有很多Person(s)
我已经在Xcode Beta-3下testing了这个解决scheme,并且这个工作正常!
此代码取出部门以简化显示从angular色中访问人员和人员所需的“一对一”和“一对多”代码。
import CoreData @objc(Person) class Person: NSManagedObject { @NSManaged var name: String //One to One relationship in your Model @NSManaged var roles: Roles } @objc(Roles) class Roles: NSManagedObject { @NSManaged var role: String //One to Many relationship in your Model @NSManaged var persons: NSMutableSet } extension Roles { func addPersonsObject(value: Person) { self.persons.addObject(value) } func removePersonsObject(value: Person) { self.persons.removeObject(value) } func addPersons(values: [Person]) { self.persons.addObjectsFromArray(values) } func removePersons(values: [Person]) { for person in values as [Person] { self.removePersonsObject(person) } } }
你可以使用一个types的Set
而不是更容易。 在上一个答案中@Nycen和@ lehn0058提供的示例之后,您可以只写:
extension PersonModel { @NSManaged var parents: Set<ParentModel>? }
然后使用Set
的insert
和remove
方法。
从Xcode 8和Swift 3.0开始,Xcode现在生成关系访问器。 例如,我有一个NSManagedObject类的商店,它与项目有一对多的关系; 我把这个关系叫做SellsItems。 现在,商店生成的类具有以下扩展来添加和从SellsItems中删除。 向关系中添加或删除项目与调用这些函数一样简单。
// MARK: Generated accessors for sellsItems extension Store { @objc(addSellsItemsObject:) @NSManaged public func addToSellsItems(_ value: Item) @objc(removeSellsItemsObject:) @NSManaged public func removeFromSellsItems(_ value: Item) @objc(addSellsItems:) @NSManaged public func addToSellsItems(_ values: NSSet) @objc(removeSellsItems:) @NSManaged public func removeFromSellsItems(_ values: NSSet) }
因为你现在只需要设置关系的一个方面,如果你有一个1 < – >多的关系,例如一个Department对象有多个Person对象,那么你就可以使用:
aPerson.department = aDepartment
如果你检查你会发现aDepartment.people(假设这是你build立的相互关系)现在将包含'aPerson'Person对象。
如果关系很多,那么上面的一个更复杂的解决scheme似乎是必要的。
假设您有以下实体:
- 人
- angular色
- 部
在你的Person
实体中,他们与Role
有一个多对多的关系,并且与Department
有一个关系。 您的托pipe对象可能如下所示:
class Person : NSManagedObject { @NSManaged var roles : Array<Role> @NSManaged var department : Department }
与反向的关系(都应该有它们)只需要为要build立的链接设置一个方面。
例如,如果将Person
的department
属性设置为Department
对象,则Department.people
的逆向属性现在也将包含此Person
对象。