ioscore-datamogenerator

iOS CoreData+MoGenerator: How do I initialize a Managed Object once only when I am using nested contexts?


I am using mogenerator to generate code from a model with a TestPerson managed object. TestPerson inherits from the abstract object TLSyncParent. In TLSyncParent I have the code:

- (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);
    }
}

I create the TestPerson object in childMOC whose parent is mainMOC, whose parent is rootMOC. awakeFromInsert runs as expected and makes the init changes. When I save childMOC to mainMOC, awakeFromInsert is run again. From the docs I would not expect that, but there is some ambiguity. From the Docs, "You typically use this method to initialize special default property values. This method is invoked only once in the object's lifetime." The real problem is that when awakeFromInsert runs in mainMOC, the init changes made in childMOC are NOT there. awakeFromInsert is apparently run before the save actually takes place.

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;
})

What is the proper place to initialize a managed object when using the MoGenerator structure?


Solution

  • OK, thanks to Tom Herrington, I found a very nice way to do this. It seems to do exactly what I want with a minimum of trouble. It fits perfectly with the MoGenerator structure. I already had a category on NSManagedObject with the method initWithMOC. I added a call to the method awakeFromCreate and provided a default implementation. You just override awakeFromCreate in the same way you would override awakeFromInsert. The only requirement is that you ALWAYS create the MO using the initWithMOC method.

    @implementation NSManagedObject (CoreDataController)
    
    + (NSManagedObject*) initWithMOC: (NSManagedObjectContext*) context
    {
        NSManagedObject* mo = (NSManagedObject*)
                [NSEntityDescription insertNewObjectForEntityForName: NSStringFromClass(self)
                                              inManagedObjectContext: context];
    
        [mo awakeFromCreate];
        return mo;
    }
    
    - (void) awakeFromCreate
    {
        return;
    }