0

我正在使用 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 按预期运行并进行初始化更改。当我将 childMOC 保存到 mainMOC 时,awakeFromInsert 再次运行。从文档中我不会想到这一点,但有一些模棱两可。从文档中,“您通常使用此方法来初始化特殊的默认属性值。此方法在对象的生命周期中仅调用一次。” 真正的问题是,当 awakeFromInsert 在 mainMOC 中运行时,在 childMOC 中所做的初始化更改不存在。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 结构时初始化托管对象的正确位置是什么?

4

3 回答 3

4

上的文档awakeFromInsert有些过时,并没有反映嵌套上下文的现实。当它说方法是

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

它实际上应该说类似“..first 插入任何托管对象上下文”,因为(正如您所发现的)这种情况在嵌套上下文中不止一次发生。确实,在使用嵌套上下文时, 的概念awakeFromInsert有点过时了。该方法显然是在旧的非嵌套时代设计的,并且没有适应。

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

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

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

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

于 2013-10-02T20:59:04.750 回答
1

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

于 2013-10-02T19:37:00.203 回答
-3

好的,感谢 Tom Herrington,我找到了一个非常好的方法来做到这一点。它似乎以最少的麻烦做我想做的事。它与 MoGenerator 结构完美契合。我已经使用 initWithMO​​C 方法在 NSManagedObject 上创建了一个类别。我添加了对方法 awakeFromCreate 的调用并提供了默认实现。您只需以与覆盖 awakeFromInsert 相同的方式覆盖 awakeFromCreate。唯一的要求是您始终使用 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;
}
于 2013-10-02T21:43:48.837 回答