如何构建 plist 文件来填充核心数据关系模型

How to build a plist file to populate a Core Data relational model

我正在构建一个 Core Data IOS 应用程序,出于测试目的,我创建了一个包含演示数据的 PLIST 文件。我的核心数据模型包含多个实体,当然还有多个关系。

就像我说的,我能够创建 PLIST 并在第一次启动时自动加载数据,但我能够 "pre-build" 关系。

我的问题是:这可以做到吗?如果可以,怎么做?

我只是看不出如何将一个键的值设置为另一个对象...

如有任何帮助,我们将不胜感激。

与此同时,我会考虑尝试使用 "dummy indexes" 重新创建这些关系,如果我能成功的话。

好吧,"Dummy Index" 方法在时尚之后奏效了

知道每个对象在我的字典数组中的位置(索引),我能够在用适当的数据加载我的实体后设置所需的关系。

顺便说一句,对于试图完成同样事情的人,这是我采取的程序:

  1. 在 XCode 中创建一个新的 PLIST 文件(文件 -> 新建 -> 文件 -> IOS 资源 -> 属性 列表)
  2. 填充 PLIST:
    • 在 Root 下,为我的数据模型中的每个实体添加了一个 ARRAY 项。
    • 在每个 ARRAY 中,为每个实体对象添加了一个 DICTIONARY 项。
    • 在每个词典中,添加了反映属性名称、类型和值的项目。
  3. 在我的第一个 TableViewController 的 ViewDidLoad 方法下添加了以下行:

    if ([[self.fetchedResultsController fetchedObjects] count] < 1)
    {
        [Utilities loadDefaultDataInManagedObjectContext:self.managedObjectContext];
    }
    
  4. 我的"loadDefaultDataInManagedObjectContext:(NSManagedObjectContext *)context"方法:

    + (void)loadDefaultDataInManagedObjectContext:(NSManagedObjectContext *)context
    {
        NSError *errorDesc = nil;
        NSPropertyListFormat format;
        NSString *plistPath;
        NSString *rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    
        plistPath = [rootPath stringByAppendingPathComponent:@"DefaultData.plist"];
    
        if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
        {
            plistPath = [[NSBundle mainBundle] pathForResource:@"DefaultData" ofType:@"plist"];
        }
    
        NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
        NSDictionary *entities = (NSDictionary *)[NSPropertyListSerialization propertyListWithData:plistXML options:NSPropertyListMutableContainers format:&format error:&errorDesc];
        if (!entities)
        {
            NSLog(@"Error reading plist: %@, format: %lu", errorDesc, format);
        }
        else
        {
            // ENTITY 1 data
            NSArray *entityNames = [entities valueForKey:@"EntityName"];
            for (NSDictionary *entityName in entityNames)
            {
                EntityName *newEntity = [NSEntityDescription insertNewObjectForEntityForName:@"EntityName" inManagedObjectContext:context];
                newEntity.attributeName1  = [entityName valueForKey:@"attributeName1"];
                newEntity.attributeName2  = [entityName valueForKey:@"attributeName2"];
            }
    
            // ENTITY 2 data
            //...
    
            // ENTITY 3 data
            //...
    
            NSError *error = nil;
            if (![context save:&error])
            {
                /*
                 Replace this implementation with code to handle the error appropriately.
    
                 abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
                 */
    
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
           }
        }
        NSLog(@"Loaded Default Data");
    
        [Utilities setRelationshipsInManagedObjectContext:context];
    }
    
  5. 我的"setRelationshipsInManagedObjectContext:(NSManagedObjectContext *)context"方法:

    + (void)setRelationshipsInManagedObjectContext:(NSManagedObjectContext *)context
    {
        NSError *error;
    
        // Initialize all neccessary fetch requests
        NSFetchRequest  *entityName1Request = [[NSFetchRequest alloc] initWithEntityName:@"entityName1"];
        entityName1Request.predicate = nil;
        NSFetchRequest  *entityName2Request = [[NSFetchRequest alloc] initWithEntityName:@"entityName2"];
        entityName2Request.predicate = nil;
        NSFetchRequest  *entityName3Request = [[NSFetchRequest alloc] initWithEntityName:@"entityName3"];
        entityName3Request.predicate = nil;
        //...
    
        NSArray *entities1  = [context executeFetchRequest:entityName1Request error:&error];
        NSArray *entities2  = [context executeFetchRequest:entityName2Request error:&error];
        NSArray *entities3  = [context executeFetchRequest:entityName3Request error:&error];
        //...
    
        // Declaring my Objects
        Entity1 *entity1;
        Entity1 *entity2;
        Entity1 *entity2;
        // ...
    
        if (entities1)
        {
            for (entity1 in entities1)
            {
                // set the required relationship according to your data and schema
                if ([entity1.attributeName1 isEqualToString:@"Whatever"])
                {
                    entity2 = (Entity2 *)[entities2 objectAtIndex:0];
                    entity1.relatedAttribute = entity2;
                }
                else if ([entity1.attributeName1 isEqualToString:@"SomethingElse"])
                {
                    entity3 = (Entity3 *)[Entities3 objectAtIndex:2];
                    [entity1 addEntity3Object:entity3]; // for to many relationships
                }
                else // ... 
                {
                }
            }
        }
    
        // repeat the same process for your other entities that contain relationship
    
        if (![context save:&error])
        {
            /*
             Replace this implementation with code to handle the error appropriately.
    
             abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
             */
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
        NSLog(@"Set relationships");
    }
    

仍然希望有人确认或否认在 PLIST 中执行所有这些操作的可能性。

TIA,

米歇尔