Reputation: 121
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:
Here is my 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
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