1
votes

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 :

  • I copied preload.xml in my project.

  • In the initWithType:error: method (the method called when a new document is created), have the following code :

    NSURL *preloadURL = [NSURL fileURLWithPath:[[NSBundle mainBundle]
                                                pathForResource:@"preload"
                                                ofType:@"xml"]];
    NSError* err = nil;
    
    [self readFromURL:preloadURL
               ofType:@"xml"
                error:&err] ;
    

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.

1
Did you override readFromURL:ofType:error:? If so, what does your version look like?Tom Harrington
Yes, I override readFromURL but it does not work. I did something else, since : create a new store (associated to my preload.xml), a new storeCoord and a new MOC. Then, I had a clone my objects between the two MOC, which is not so great... But it seems to work.Colas
Well, it sounds like the original problem is somehow related to your readFromURL:ofType:error: code, and since you didn't include that it's hard to say what might be wrong with it.Tom Harrington
No sorry, I didn't override at all readFromURL !!! I meant : yes, I used readFromURL. Sorry for the misunderstanding :/Colas

1 Answers

1
votes

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