Populating The Core Data Store With Predefined Data

In my previous article, I’ve shown you a way to turn your managed objects into a dictionary, and vice-versa. In this article, we’ll use that code to populate the Core Data store with data stored in plain-text files in your project’s bundle. We’ll use JSON for representing our objects, but you can generally use any format/library combination that is capable of converting a file into a dictionary. (For example, an XML/NSXMLParser combo.)

The library I’ll use for this example is the excellent TouchJSON library by jwight and buddies. It’s under an MIT license.

Let’s say you have a bunch of template objects that you need pre-loaded in your database upon application’s first launch. You could use these objects later on to instantiate some other objects. Every template object gets its own .template file, holding a JSON representation of the object. The idea here is that your code walks through all the .template files in your app bundle, and loads each JSON object into your Core Data store. Pretty simple stuff.

So, the assumptions are:

  1. The TouchJSON library is copied into your project tree.
  2. You have the dictionary conversion code from my previous article set up and working.
  3. The .template files are added to your project, and are listed in the “Copy Bundle Resources” build phase of your current target.
  4. Each of the .template files holds a single object from your model, represented in JSON format.

For (boring) example, if you have an Employee object with name and address properties, and a relation to a Department object, which in turn has a name property, your JSON representation for an employee would look like:

{
    "class": "Employee",
    "name": "John Johnson",
    "address": "",
    "department": {
        "class": "Department",
        "name": "Boring Department"
    }
}

If you want to do it the other way around, you could define a .template for each department, and fill it with employees:

{
    "class": "Department",
    "name": "Boring Department",
    "employees": [
        {
            "class": "Employee",
            "name": "John Johnson",
            "address": ""
        },
        {
            "class": "Employee",
            "name": "Jane Jansen",
            "address": "21 Nice Avenue"
        }
    ]
}

Notice the “class” attribute. It is a special attribute that the createManagedObjectFromDictionary:inContext: function uses so that it knows the type of object it is about to instantiate and put into a store. You must specify this attribute, otherwise the code will fail.

One small disclaimer though: this approach doesn’t allow complex relationship graphs (or many-to-many relationships), since there’s no way you can reference the same object twice in JSON. So, for example if you’d like an employee to belong to two departments, and then make another employee belong to the same two departments, you would fail. You should consider a different approach than the one described here, if having many-to-many relationships (or any other form of non-trivial relationships) is a requirement for you.

Once you have all of the above taken care of, the actual code is dead simple:

NSArray* templates = [[NSBundle mainBundle] pathsForResourcesOfType:@"template" inDirectory:nil];

for (NSString* template in templates) {
    NSError *error;
    NSData* jsonData   = [NSData dataWithContentsOfFile:template];
    NSDictionary* dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];

    if (error) {
        // ... (handle the error)

        continue;
    }

    [ExtendedManagedObject createManagedObjectFromDictionary:dict inContext:context];
}

Add this to your first-run code, and voila.

Leave a Reply