如何在使用嵌套上下文时自动设置Core Data关系

And*_*sen 10 macos cocoa core-data objective-c ios

我正在努力找到一个合适的解决方案来解决在核心数据中使用嵌套的托管对象上下文时出现的问题.采用具有两个enites的模型,Person和Name,其中每个Person与Name具有一对一的关系,而Name的person关系不是可选的.以前,在Person的-awakeFromInsert方法中,我会自动为新Person创建一个Name实体:

- (void)awakeFromInsert
{
    [super awakeFromInsert];

    NSManagedObjectContext *context = [self managedObjectContext];
    self.name = [NSEntityDescription insertNewObjectForEntityForName:@"Name" inManagedObjectContext:context];
}
Run Code Online (Sandbox Code Playgroud)

这在单个非嵌套的托管对象上下文中工作得很好.但是,如果上下文具有父上下文,则在保存子上下文时,将在父上下文中创建新的Person对象,并在复制原始Person的属性和关系之前-awakeFromInsert再次在此新对象上调用该对象.因此,创建另一个Name对象,然后在复制现有名称关系时"断开连接".保存失败,因为浮动Name的now-nil 关系验证失败.此处以及其他地方描述了此问题.person

到目前为止,我一直无法找到解决这个问题的好方法.在getter方法中懒惰地创建关系实际上会导致同样的问题,因为当在父上下文中创建新Person时,内部Core Data机制会调用getter.

我唯一能想到的就是放弃自动关系生成,并且总是在创建Person的控制器类中显式创建关系,或者在+[Person insertNewPersonInManagedObjectContext:]仅由我的代码调用的方便方法(例如)中创建关系,并始终用于显式创建新Person对象的方法.也许这是最好的解决方案,但我宁愿不必如此严格,只允许使用单个方法来创建托管对象,当我无法控制的其他创建方法和其使用我不能容易检查/排除,存在.首先,它将意味着多个NSArrayController子类来自定义它们创建托管对象的方式.

是否有其他遇到此问题的人提出了一个优雅的解决方案,允许一个NSManagedObject在创建/插入时自动创建关系对象?

And*_*sen 1

我最终选择了便捷方法解决方案。我的应用程序中的所有 NSManagedObject 子类都有一个+insertInManagedObjectContext:方法。创建这些对象的实例(在我自己的代码中)始终使用该方法完成。在该方法中,我这样做:

+ (instancetype)insertInManagedObjectContext:(NSManagedObjectContext *)moc
{
    MyManagedObject *result = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntityName" inManagedObjectContext:moc]
    [result awakeFromCreation];
    return result;
}

- (void)awakeFromCreation
{
    // Do here what used to be done in -awakeFromInsert.
    // Set up default relationships, etc.
}
Run Code Online (Sandbox Code Playgroud)

至于 NSArrayController 问题,解决这个问题一点也不坏。我只是创建了 NSArrayController 的子类,覆盖-newObject,并将该子类用于我的应用程序中的所有相关 NSArrayController:

@implementation ORSManagedObjectsArrayController

- (id)newObject
{
    NSManagedObjectContext *moc = [self managedObjectContext];
    NSEntityDescription *entity = [NSEntityDescription entityForName:[self entityName]
                                              inManagedObjectContext:moc];
    if (!entity) return nil;

    Class class = NSClassFromString([entity managedObjectClassName]);
    return [class insertInManagedObjectContext:moc];
}

@end
Run Code Online (Sandbox Code Playgroud)