如何将对象添加到Swift中NSManagedObject
子类中的关系属性?
在Objective-C中,当您从数据模型中生成Xcode中的NSManagedObject
子类时,会自动生成类扩展,其中包含如下声明:
@interface MyManagedObject (CoreDataGeneratedAccessors)
- (void)addMySubObject: (MyRelationshipObject *)value;
- (void)addMySubObjects: (NSSet *)values;
@end
然而,Xcode目前缺乏Swift类的这一类生成功能。
如果我尝试直接在Swift对象上调用等效方法:
myObject.addSubObject(subObject)
...我在方法调用上遇到编译器错误,因为这些生成的访问器不可见。
我已将关系属性声明为@NSManaged
,如文档中所述。
或者我是否必须为具有关系的数据模型恢复Objective-C对象?
答案 0 :(得分:46)
从Xcode 7和Swift 2.0(参见release note #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 符合键值编码的兼容多种访问器。
添加此定义将允许您向集合中添加项目。不确定为什么这些不仅仅是自动生成......
答案 1 :(得分:32)
是的,它不再起作用了,Swift无法以这种方式在运行时生成访问器,它会破坏类型系统。
您需要做的是使用关键路径:
var manyRelation = myObject.valueForKeyPath("subObjects") as NSMutableSet
manyRelation.addObject(subObject)
/* (Not tested) */
答案 2 :(得分:19)
Objective C中的核心数据自动创建setter方法(1):
默认情况下,Core Data为托管对象类的建模属性(属性和关系)动态创建有效的公共和原始get和set访问器方法。这包括键值编码可变代理方法,如addObject:和removed:,详见mutableSetValueForKey的文档: - 托管对象是所有多对多关系的有效可变代理。
目前Xcode6-Beta2中的Swift一直存在,你必须自己实现这些访问者。例如,如果您与Way
到Node
之间存在无序的多对多关系,则可以像这样实施addNodesObject
:
class Way : NSManagedObject {
@NSManaged var nodes : NSSet
func addNodesObject(value: Node) {
self.mutableSetValueForKey("nodes").addObject(value)
}
}
此处的关键是您必须使用mutableSetValueForKey
/ mutableOrderedSetValueForKey
/ mutableArrayValueForKey
。在这些集/数组上,您可以调用addObject,它们将存储在下一次刷新中。
答案 3 :(得分:6)
扩展解决方案上面的一对多关系是NSMutableSet所以这允许你直接在角色中添加或删除Person NSManagedObject,在这种情况下,Person有一个角色,角色有很多Person
我已经在Xcode Beta-3下测试了这个解决方案,这很有效!
此代码取出部门,以简化显示从角色的人员和角色访问角色所需的一对一和一对多代码。
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)
}
}
}
答案 4 :(得分:6)
您可以使用键入的Set
代替,这样更容易。按照@Nycen和@ lehn0058在上一个答案中提供的示例,您可以写:
extension PersonModel {
@NSManaged var parents: Set<ParentModel>?
}
然后使用insert
的{{1}}和remove
方法。
答案 5 :(得分:5)
从Xcode 8和Swift 3.0开始,Xcode现在为关系生成访问器。例如,我有一个NSManagedObject类Store,它与Items有一对多的关系;我称这种关系为SellsItems。现在,Store的生成类具有以下扩展名,可以从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)
}
答案 6 :(得分:3)
由于你现在只需设置一个关系的一方来设置两者,如果你有一个很多的关系,那就特别简单,例如:一个Department对象有多个Person对象,那么你可以使用:
aPerson.department = aDepartment
如果你检查一下你会发现aDepartment.people(假设你已经建立的互惠关系)现在将包含“aPerson”和#39; aPerson&#39;人物对象。
如果关系很多&lt; - &gt;很多,那么上面一个更复杂的解决方案似乎是必要的。
答案 7 :(得分:-1)
我们假设你有以下实体:
在您的Person
实体中,他们与Role
以及与Department
的一对一有很多关系。您的托管对象可能如下所示:
class Person : NSManagedObject
{
@NSManaged var roles : Array<Role>
@NSManaged var department : Department
}
与反转的关系(都应该拥有它们)只需要为要建立的链接设置一侧。
例如,如果您将Person
的{{1}}属性设置为department
对象,则反Department
属性现在也将具有此Department.people
属性Person
1}}包含在里面的对象。