你如何打印出 Core Data 对象?

Posted

技术标签:

【中文标题】你如何打印出 Core Data 对象?【英文标题】:How do you print out Core Data objects? 【发布时间】:2014-09-05 14:11:45 【问题描述】:

我想在 NSLog 语句的代码中打印出存储在 Core Data 对象中的数据。

背景信息:我正在从 PList 中读取数据以进行预填充,然后将其传输到 Core Data。发布的应用程序只会从 Core Data 中读取。

这是我的 PList 的样子:

这是我的对象图:

这是我的代码:

-(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;

_

像这样打印字典:

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

给我很好的分类输出,如下所示:

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;
                               ;
                           ,
                                ...

像这样打印出核心数据实体:

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

或者这个:

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

给我这个:

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

)]

我怎样才能让它看起来像字典打印输出?我能想到的最直接的方法是为每个迭代其自己的集合的实体添加一个“打印”方法。我的完整应用中有 32 个实体。我想避免每次从对象图中生成新实体时都必须编写此代码。

更有效的方法是扫描每个实体的属性并对其进行迭代。此链接显示如何为属性而不是关系执行此操作: http://iphonedevelopment.blogspot.com/2010/08/core-data-odds-and-ends.html

你如何使这种关系适用于人际关系?

【问题讨论】:

【参考方案1】:

最简单的方法是

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

你会得到一些额外的不那么漂亮的核心数据输出,但如果是用于信息或调试,应该没问题。此外,这些关系可能未完全记录。

更好的是,创建一个像prettyDescription 这样的方法,您可以在其中根据自己的喜好格式化输出。您可以将其放入 NSManagedObject 子类或(更好)其扩展中。

-(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

现在您可以使用

记录所有食谱
for (Recipe *r in recipesObject.recipe)  NSLog(@"%@", r.prettyDescription); 

注意:为了清楚起见,我认为您应该重命名实体和属性,如下所示:

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

【讨论】:

感谢您的回答,感谢您建议的重命名约定。 这似乎是一种干净的方法。但是,我的完整对象图中有许多实体类(总共 32 个,这只是一个示例部分),并且为每个类手动创建一个 prettyDescription 需要大量工作。此外,每当我更改对象图和自动生成实体类时,我都必须再次添加代码。有没有办法在继承的 NSManagedObject 中创建一个 prettyDescription 并打印任何类型实体的所有属性? 我认为可以将其抽象出来,但肯定也不是不费吹灰之力。一个实用的替代方法是使用 description 并手动添加关系的 descriptions

以上是关于你如何打印出 Core Data 对象?的主要内容,如果未能解决你的问题,请参考以下文章

opencv:使用 cout 和 Mat 对象抛出异常

如何删除 Core Data 存储中除一个对象之外的所有对象?

如何通过 NSPredicate 过滤 Core Data 托管对象?

RestKit 到 Core Data 的映射和加载零对象。 RKManagedObjectLoader

如何取消删除 Core Data 中标记为删除的托管对象?

打印包含 S4 对象列表列的 data.frame