Black Orchid
Black Orchid

Reputation: 121

How do you print out Core Data objects?

I would like to print out the data stored in Core Data objects in code in an NSLog statement.

Background info: I am reading data from a PList for pre-population, then transfering it to Core Data. The released app will only read from Core Data.

Here's what my PList looks like:

Recipes.plist

Here is my object graph:

object graph

Here is my code:

-(void)initXML
{
    [self deleteAllEntities:@"Recipes"];

    [self copyXMLtoEntities];

    [self printEntities];
}

_

// deletes data from all entities to ready them for pre-population
-(void)deleteAllEntities:(NSString *)entityDescription
{
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityDescription inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    NSError *error;
    NSArray *items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

    for (NSManagedObject *managedObject in items)
    {
        [self.managedObjectContext deleteObject:managedObject];
        DLog(@"%@ ..object deleted", entityDescription);
    }

    if (![self.managedObjectContext save:&error])
    {
        DLog(@"Error deleting %@ - error:%@", entityDescription, error);
    }
}

_

// This copies data from the PList to Core Data Entities, aka pre-population
-(void)copyXMLtoEntities
{        
    NSDictionary *allRecipesDictionary = [self getRecipes];
    DLog(@"allRecipes: [%@]", allRecipesDictionary);

    Recipes *recpies = [NSEntityDescription insertNewObjectForEntityForName:@"Recipes" inManagedObjectContext:self.managedObjectContext];

    for (NSString *recipeKey in allRecipesDictionary)
    {
        NSDictionary *recipeDict = [allRecipesDictionary objectForKey:recipeKey];

        Recipe *recipe = [NSEntityDescription insertNewObjectForEntityForName:@"Recipe" inManagedObjectContext:self.managedObjectContext];
        recipe.id = recipeKey;
        recipe.name = [recipeDict objectForKey:@"name"];

        NSMutableArray *contentItemsArray = [[NSMutableArray alloc] init];            

        NSArray *contentArrayToIterate = [recipeDict objectForKey:@"content"];            

        // loop through content array and add each item
        for (int i=0 ; i < [contentArrayToIterate count] ; i++)
        {
            // create text or image content items
            // add them to the array
            // create entities and add them to contentItemsArray

            NSDictionary *contentItemDict = contentArrayToIterate[i];

            NSDictionary *textItemDict = [contentItemDict objectForKey:@"textItem"];
            NSDictionary *imageItemDict = [contentItemDict objectForKey:@"imageItem"];
            NSString *sequenceStr = [contentItemDict objectForKey:@"sequence"];

            if (textItemDict != nil)
            {
                NSString *text = [textItemDict objectForKey:@"text"];
                TextItem *textItem = [NSEntityDescription insertNewObjectForEntityForName:@"TextItem" inManagedObjectContext:self.managedObjectContext];

                textItem.text = text;
                textItem.sequence = sequenceStr;

                // add entity to the array
                [contentItemsArray addObject:textItem];
            }

            if (imageItemDict != nil)
            {
                NSString *filename = [imageItemDict objectForKey:@"filename"];

                ImageItem *imageItem = [NSEntityDescription insertNewObjectForEntityForName:@"ImageItem" inManagedObjectContext:self.managedObjectContext];

                imageItem.filename = filename;
                imageItem.sequence = sequenceStr;

                // add entity to the array
                [contentItemsArray addObject:imageItem];
            }
        } // loop through content

        recipe.contentItems = [NSSet setWithArray:contentItemsArray];
        [recpies addRecipeObject:recipe];
    } // loop through recipes

    [self saveContext];
}

_

// This returns the Dictionary of Recipes
-(NSDictionary *)getRecipes
{
    NSString *path = [[NSBundle mainBundle] pathForResource:@"Recipes" ofType:@"plist"];
    NSDictionary *plist = [[NSDictionary alloc] initWithContentsOfFile:path];

    // recipes
    NSDictionary *recipes = [plist objectForKey:@"Recipes"];

    return recipes;
}

_

Printing a dictionary like this:

DLog(@"allRecipes: [%@]", allRecipesDictionary);

Gives me nicely categorized output like this:

allRecipes: [{
    "BLUEBERRY_PIE_001" =     {
        content =         (
                           {
                               textItem =                 {
                                   sequence = 1;
                                   text = "Mix sugar, cornstarch, salt, and cinnamon, and sprinkle over blueberries.";
                               };
                           },
                           {
                               imageItem =                 {
                                   filename = "mixIngredients.jpg";
                                   sequence = 2;
                               };
                           },
                                ...

Printing out Core Data Entities either like this:

DLog(@"self.recipes: [%@]", self.recipes);

or this:

DLog(@"| self.recipes description: [%@]", [self.recipes description]);

Gives me this:

self.recipes: [(
"<Recipes: 0x9951840> (entity: Recipes; id: 0x9962730 <x-coredata://4E308A08-FB8A-44C5-887A-88C335378A14/Recipes/p2> ; data: {\n    recipe =     (\n    );\n})"

)]

How can I get it to look like the dictionary printout? The straightforward way I can think of is add a "print" method to each entity that iterates over its own sets. I have 32 entities in my full app. I would like to avoid having to write this code every time I spawn new entities from the object graph.

A more efficient way would be to scan the attributes of each Entity and iterate over them. This link shows how to do this for attributes but not for relationships: http://iphonedevelopment.blogspot.com/2010/08/core-data-odds-and-ends.html

How do you make this work for relationships?

Upvotes: 1

Views: 3125

Answers (1)

Mundi
Mundi

Reputation: 80265

The easiest way is

for (Recipe *r in recipesObject.recipe) { NSLog(@"%@", r); }

You will get some additional not so pretty core data output, but if it is for info or debugging, it should be fine. Also, the relationships might not be completely logged.

Better, create a method like prettyDescription in which you format the output to your liking. You can put this into the NSManagedObject subclass or (better) an extension thereof.

-(NSString*)prettyDescription {
    NSMutableString *result = [NSMutableString new];
    [result appendString:self.name];
    [result appendString:@"\n"];
    for (ContentItem *item in self.contentItems) {
        // append details from item to the result
    }
    return [NSString stringWithString:result]; // return immutable string
}

Now you can log all recipes with

for (Recipe *r in recipesObject.recipe) { NSLog(@"%@", r.prettyDescription); }

NB: I think you should rename your entities and attributes for clarity as follows:

Recipes          --> RecipesCollection
Recipes.recipe   --> RecipesCollection.recipes
Recipe.recipes   --> Recipe.collection 

Upvotes: 1

Related Questions