Question

I'm using Core Data with a somewhat complex data model. There are many places where the string attributes are going to be unset and apparently Core Data returns nil in these cases when retrieving the attribute. I'd like to generally override this behavior so that if any string attribute of the data model would return nil it'll return an empty string instead.

On top of Core Data I'm using both mogenerator and Magical Record. All of the entities in my data model inherit either directly or indirectly from an AbstractEntity, so I'm hoping that I can edit mogenerator's human file to somehow capture calls up the line, regardless of whether they use KVC or method calls, and return an empty string if the string attribute is nil. There are similar situations where I'd want to return an empty string if an integer attribute has zero.

Is this possible? Or do I have to override each attribute individually?

Was it helpful?

Solution

It sounds like what you really want is to make the default value for string attributes be an empty string. In most cases you can set a default value for an attribute in the Core Data model editor. That value is automatically assigned to that attribute any time you create a new managed object. But the editor doesn't support using an empty string as the default, so you can't do it there.

You can make the default value an empty string at run time, though. Data models are editable until you start using them. So a good place to do it is immediately after you create the model object. The following will assign an empty string as the default value for every string attribute in a data model:

- (NSManagedObjectModel *)managedObjectModel
{
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyModel" withExtension:@"momd"];
    _managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];

    NSEntityDescription *entityDescription = [_managedObjectModel entitiesByName][@"Entity"];
    for (NSString *attributeName in [entityDescription attributesByName]) {
        NSAttributeDescription *attributeDesc = [entityDescription attributesByName][attributeName];
        if ([attributeDesc attributeType] == NSStringAttributeType) {
            [attributeDesc setDefaultValue:@""];
        }
    }

    return _managedObjectModel;
}

Use this or something like it, and every string attribute in your model will automatically be an empty string when you create new instances. If you don't want to do this for every string attribute, edit the code to add some extra checks for entity and/or attribute name.

OTHER TIPS

Tom's solution is what I used, but in a slightly different way. Since I'm using Magical Record for most of the Core Data access, my app delegate doesn't have a managedObjectModel property. However, by putting similar code to his in the CVCAbstractEntity class generated by mogenerator, in the -awakeFromInsert method, the problem was solved nicely.

It's slightly less elegant than Tom's solution in a way, in that although the default values really should be empty strings, this instead sets string attributes to empty strings when the managed objects are created. But unless I wanted to change the code for the Magical Record categories, this solution worked better for me.

Here's the code I added to -awakeFromInsert.

NSManagedObjectModel *mom = [NSManagedObjectModel defaultManagedObjectModel];
NSEntityDescription *entityDesc = [[mom entitiesByName] objectForKey:[self entityName]];
for (NSString *attributeName in [entityDesc attributesByName]) {
  NSAttributeDescription *attrDesc = [[entityDesc attributesByName] objectForKey:attributeName];
  if ([attrDesc attributeType] == NSStringAttributeType) {
    [self setValue:@"" forKey:attributeName];
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top