How do I set default values on new properties for existing entities after light weight core data migration?
Asked Answered
J

2

30

I've successfully completed light weight migration on my core data model.

My custom entity Vehicle received a new property 'tirePressure' which is an optional property of type double with the default value 0.00.

When 'old' Vehicles are fetched from the store (Vehicles that were created before the migration took place) the value for their 'tirePressure' property is nil. (Is that expected behavior?)

So I thought: "No problem, I'll just do this in the Vehicle class:"

- (void)awakeFromFetch {
    [super awakeFromFetch];
    if (nil == self.tirePressure) {
        [self willChangeValueForKey:@"tirePressure"];
        self.tirePressure = [NSNumber numberWithDouble:0.0];
        [self didChangeValueForKey:@"tirePressure"];
    }
  }

Since "change processing is explicitly disabled around" awakeFromFetch I thought the calls to willChangeValueForKey and didChangeValueForKey would mark 'tirePresure' as dirty.

But they don't.

Every time these Vehicles are fetched from the store 'tirePressure' continues to be nil despite having saved the context.

Juniper answered 3/5, 2011 at 9:7 Comment(0)
J
84

I finally figured it out after 6 months.

The attributes that are added to a core data entity have to be marked as non-optional. Only then will the default values be set automatically during lightweight migration for the entities that were created with the old data model.

Juniper answered 31/10, 2011 at 11:47 Comment(3)
6 months! Very grateful you came back and answered.Whereinto
great!! 6 months ... LOLCatchy
This answer helped us !!!Pardew
D
1

You need to use setPrimativeValueForKey in awakeFromFetch because the dynamic accessor used by self.propertyName is not yet active.

However, since the default value is not appearing in the first place, that suggest your migration failed in detail. You may need to create a migration map to ensure the migration is completely successful.

Dannica answered 3/5, 2011 at 14:31 Comment(4)
Are you sure about this? The docs for awakeFromFetch say that "you can use public setters to establish transient values." That leads me to believe that dynamic accessors are in place. Using setPrimitiveValueForKey wrapped in willChangeValueForKey and didChangeValueForKey did NOT 'dirty' the object so I could save the change.Juniper
The docs say "The managed object context’s change processing is explicitly disabled around this method so that you can use public setters to establish transient values and other caches without dirtying the object or its context." The problem is that the object is not yet being observed so no object is being notified of any changes.Dannica
The real issue here is that you shouldn't have to create a default value in code. The model, properly migrated, should do it for you.Dannica
Ah, thanks for clarifying this. Well I was willing to accept the default values not being there as a trade-off for not having to do the migration by hand. ATM I'm willing to just set the default value every time the object is fetched which gives me what I need in the runtime with a performance penalty.Juniper

© 2022 - 2024 — McMap. All rights reserved.