macoscocoacore-datapreloadnspersistentdocument

How to preload data from Core Data in a NSPersistentDocument?


I have a NSPersistentDocument with a given Core Data model, etc.

I have a file, created by this document, let's say it its preload.xml. It "contains" several NSManagedObjects.

I would like to load these objects in all my new documents, so that when I create a new document, the new document automatically "has" the objects "living" in preload.xml. So far, here is what I did :

This doesn't work because, when I try afterwards to save my document to, let's say myNewDoc.xml, this file is empty but all my new data is saved to preload.xml.

I am wondering if I need to create a new store or contextor storeCoordinator or something else. I never dealt with such objects since I always used NSPersistentDocument.


Solution

  • Get the saved objects :

        NSPersistentStoreCoordinator * newPersStoreCoord ;
        newPersStoreCoord = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:theDoc.managedObjectModel] ;
    
        NSString * path = [[NSBundle mainBundle] pathForResource:@"preload"
                                                          ofType:@"xml"];
        NSURL *preloadURL = [NSURL fileURLWithPath:path];
    
    
    
        [newPersStoreCoord addPersistentStoreWithType:NSBinaryStoreType
                                        configuration:nil
                                                  URL:preloadURL
                                              options:nil
                                                error:NULL] ;
    
        NSManagedObjectContext * auxMOC = [[NSManagedObjectContext alloc] init] ;
        [auxMOC setPersistentStoreCoordinator:newPersStoreCoord] ;
    

    copy them to your "living" MOC

      [self loadPreloadedDataFromTheMOC:auxMOC
                                 toTheMOC:theDoc.managedObjectContext
                                forTheDoc:theDoc] ;
    

    with the help of cloning techniques

    - (NSManagedObject *)cloneInContext:(NSManagedObjectContext *)context
                        withCopiedCache:(NSMutableDictionary *)alreadyCopied
                         exludeEntities:(NSArray *)namesOfEntitiesToExclude
                      excludeAttributes:(NSArray *)namesOfAttributesToExclude
    {
        NSString *entityName = [[self entity] name];
    
        if ([namesOfEntitiesToExclude containsObject:entityName])
        {
            return nil;
        }
    
        NSManagedObject *cloned = [alreadyCopied objectForKey:[self objectID]];
        if (cloned != nil)
        {
            return cloned;
        }
    
    
        //create new object in data store
        cloned = [NSEntityDescription insertNewObjectForEntityForName:entityName
                                               inManagedObjectContext:context];
        [alreadyCopied setObject:cloned
                          forKey:[self objectID]];
    
        //loop through all attributes and assign then to the clone
        NSDictionary *attributes = [[NSEntityDescription entityForName:entityName
                                                inManagedObjectContext:context] attributesByName];
    
    
        for (NSString *attr in attributes)
        {
            if (![namesOfAttributesToExclude containsObject:attr])
            {
                [cloned setValue:[self valueForKey:attr] forKey:attr];
            }
        }
    
        //Loop through all relationships, and clone them.
        NSDictionary *relationships = [[NSEntityDescription entityForName:entityName
                                                   inManagedObjectContext:context] relationshipsByName];
    
    
    
        for (NSString *relName in [relationships allKeys])
        {
            NSRelationshipDescription *rel = [relationships objectForKey:relName];
    
            NSString *keyName = rel.name;
    
            if ([rel isToMany])
            {
                id sourceSet ;
                id clonedSet ;
    
                /*
                 On gère selon que la relation est ordonnée ou non
                 */
                if (![rel isOrdered])
                {
                    //get a set of all objects in the relationship
                    sourceSet = [self mutableSetValueForKey:keyName];
                    clonedSet = [cloned mutableSetValueForKey:keyName];
                }
                else
                {
                    sourceSet = [self mutableOrderedSetValueForKey:keyName];
                    clonedSet = [cloned mutableOrderedSetValueForKey:keyName];
                }
    
                NSEnumerator *e = [sourceSet objectEnumerator];
                NSManagedObject *relatedObject;
    
                while (relatedObject = [e nextObject])
                {
                    //Clone it, and add clone to set
                    NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context
                                                                         withCopiedCache:alreadyCopied
                                                                          exludeEntities:namesOfEntitiesToExclude
                                                                       excludeAttributes:namesOfAttributesToExclude];
                    if (clonedRelatedObject)
                    {
                        [clonedSet addObject:clonedRelatedObject];
                    }
                }
            }
            else
            {
                NSManagedObject *relatedObject = [self valueForKey:keyName];
                if (relatedObject != nil)
                {
                    NSManagedObject *clonedRelatedObject = [relatedObject cloneInContext:context
                                                                         withCopiedCache:alreadyCopied
                                                                          exludeEntities:namesOfEntitiesToExclude
                                                                       excludeAttributes:namesOfAttributesToExclude];
                    if (clonedRelatedObject)
                    {
                        [cloned setValue:clonedRelatedObject forKey:keyName];
                    }
                }
            }
        }
    
        return cloned;
    }