iOS CoreData + MoGenerator:只有在我使用嵌套上下文时,如何初始化一个受管对象?

时间:2013-10-02 18:49:10

标签: ios core-data mogenerator

我正在使用mogenerator从具有TestPerson托管对象的模型生成代码。 TestPerson继承自抽象对象TLSyncParent。在TLSyncParent中我有代码:

- (void) awakeFromInsert
{
    [super awakeFromInsert];
    QNSLOG(@"%@\n%@", self.managedObjectContext, self.description);
    if (self.syncStatus == nil) {
        self.syncStatusValue = SYNCSTATUS_NEW;
        self.tempObjectPID = [self generateUUID];
        QNSLOG(@"After init values\n%@", self.description);
    }
}

我在childMOC中创建了TestPerson对象,其父级是mainMOC,其父级是rootMOC。 awakeFromInsert按预期运行并进行init更改。当我将childMOC保存到mainMOC时,再次运行awakeFromInsert。从我不希望的文档,但有一些模棱两可。从文档"您通常使用此方法初始化特殊的默认属性值。此方法仅在对象的生命周期内调用一次。"真正的问题是当awakeFromInsert在mainMOC中运行时,在childMOC中进行的init更改不存在。 awakeFromInsert显然在实际保存之前运行。

2013-10-02 11:22:45.510_xctest[21631:303] TestPerson -awakeFromInsert <NSManagedObjectContext: 0xd684780>
<TestPerson: 0xd6863b0> (entity: TestPerson; id: 0xd684ed0 <x-coredata:///TestPerson/t02B71E0D-AE3F-4605-8AC7-638AE072F2302> ; data: {
    dept = nil;
    job = nil;
    objectPID = nil;
    personName = nil;
    syncStatus = 0;
    tempObjectPID = nil;
    updatedAt = nil;
})
2013-10-02 11:22:45.511_xctest[21631:303] TestPerson -awakeFromInsert After init values
<TestPerson: 0xd6863b0> (entity: TestPerson; id: 0xd684ed0 <x-coredata:///TestPerson/t02B71E0D-AE3F-4605-8AC7-638AE072F2302> ; data: {
    dept = nil;
    job = nil;
    objectPID = nil;
    personName = nil;
    syncStatus = 4;
    tempObjectPID = "7AB46623-C597-4167-B189-E3AAD24954DE";
    updatedAt = nil;
})
2013-10-02 11:22:45.511_xctest[21631:303] CoreDataController -saveChildContext: Saving Child MOC
2013-10-02 11:22:45.511_xctest[21631:303] TestPerson -awakeFromInsert <NSManagedObjectContext: 0xd682180>
<TestPerson: 0xd68fce0> (entity: TestPerson; id: 0xd684ed0 <x-coredata:///TestPerson/t02B71E0D-AE3F-4605-8AC7-638AE072F2302> ; data: {
    dept = nil;
    job = nil;
    objectPID = nil;
    personName = nil;
    syncStatus = 0;
    tempObjectPID = nil;
    updatedAt = nil;
})
2013-10-02 11:22:45.511_xctest[21631:303] TestPerson -awakeFromInsert After init values
<TestPerson: 0xd68fce0> (entity: TestPerson; id: 0xd684ed0 <x-coredata:///TestPerson/t02B71E0D-AE3F-4605-8AC7-638AE072F2302> ; data: {
    dept = nil;
    job = nil;
    objectPID = nil;
    personName = nil;
    syncStatus = 4;
    tempObjectPID = "B799AFDA-3514-445F-BB6F-E4FE836C4F9D";
    updatedAt = nil;
})

使用MoGenerator结构时初始化托管对象的适当位置是什么?

3 个答案:

答案 0 :(得分:4)

awakeFromInsert上的文档有点过时,并不反映嵌套上下文的实际情况。当它说方法是

  

当接收器首次插入托管对象上下文时,由Core Data框架自动调用。

它应该说“首先插入任何托管对象上下文”,因为(正如您所发现的)这种情况不止一次发生在嵌套上下文中。实际上,awakeFromInsert的概念在使用嵌套上下文时有点过时了。该方法在旧的非嵌套日期中进行了明确设计,并未进行调整。

有几种方法可以解决这个问题。一个是简单的运行时检查,您可以执行以下操作:

if ([[self managedObjectContext] parentContext] != nil) {
    // Set default values here
}

此代码仅在当前上下文是某些其他上下文的子项时运行。该方法仍然针对父上下文运行,但是您跳过了默认值设置器。如果您只嵌套一个级别,即一个父级具有一个或多个子上下文,但没有父级的“孙子”上下文,那就没问题。如果你曾经添加过另一个嵌套级别,那么你就可以回到起点。

另一个选项(以及我通常喜欢的选项)是将默认值代码移动到单独的方法中,然后根本不使用awakeFromInsert。也就是说,创建一个名为setDefaultValues的方法,在您的情况下设置syncStatusValuetempObjectPID的值。 在您首次创建新实例后立即调用此方法,而不是其他地方。由于它永远不会自动调用,因此代码永远不会运行,除非您告诉它运行。

答案 1 :(得分:1)

我很确定Mogenerator不会改变创建托管对象的方式,但只会将实际的托管对象类移动到带有“_”前缀的机器生成的文件,并创建这些托管对象的子类以放置所有自定义逻辑输入,以便在重新生成托管对象类时不会丢失。

答案 2 :(得分:-3)

好的,感谢Tom Herrington,我找到了一个很好的方法来做到这一点。它似乎完全符合我的要求而且遇到了麻烦。它完全符合MoGenerator结构。我已经使用initWithMO​​C方法在NSManagedObject上有一个类别。我添加了对方法awakeFromCreate的调用并提供了一个默认实现。您只需覆盖awakeFromCreate,就像覆盖awakeFromInsert一样。唯一的要求是你总是使用initWithMO​​C方法创建MO。

@implementation NSManagedObject (CoreDataController)

+ (NSManagedObject*) initWithMOC: (NSManagedObjectContext*) context
{
    NSManagedObject* mo = (NSManagedObject*)
            [NSEntityDescription insertNewObjectForEntityForName: NSStringFromClass(self)
                                          inManagedObjectContext: context];

    [mo awakeFromCreate];
    return mo;
}

- (void) awakeFromCreate
{
    return;
}