Search code examples
iphonensarraynsmanagedobjectnssetwritetofile

NSManagedObject hierarchy import and export


I'm on the run to make my NSMangedObjectClass profile im-/exportable.
I try it this way
Exporting works correctly if I write the Relationships in NSArrays because NSSet doesn't have writeToFile implemented.

- (void) exportProfile:(Profile *)profile toPath:(NSString *)path{
//Profile
NSMutableDictionary *profileDict = [[self.selectedProfile dictionaryWithValuesForKeys:[[[self.selectedProfile entity] attributesByName] allKeys]] mutableCopy];
NSMutableArray *views = [NSMutableArray array];

//Views
for (View *view in selectedProfile.views) {
    NSMutableDictionary *viewDict = [[view dictionaryWithValuesForKeys:[[[view entity] attributesByName] allKeys]] mutableCopy];
    NSMutableArray *controls = [NSMutableArray array];
         //Much more for-loops
    [viewDict setObject:controls forKey:@"controls"];
    [views addObject:viewDict];
}

[profileDict setObject:views forKey:@"views"];

if([profileDict writeToFile:[path stringByStandardizingPath] atomically:YES]) 
    NSLog(@"Saved");
else
    NSLog(@"Not saved");
[profileDict release];
}

But if want to import on the other side

- (Profile*) importProfileFromPath:(NSString *)path{
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
Profile *newProfile = [NSEntityDescription insertNewObjectForEntityForName:@"Profile" inManagedObjectContext:context];

NSMutableDictionary *profileDict = [NSMutableDictionary dictionaryWithContentsOfFile:[path stringByStandardizingPath]];
[newProfile setValuesForKeysWithDictionary:profileDict];
}

I get an exception, this doesn't confuse me cause Profile expects a NSSet and no NSArray.
[__NSCFArray intersectsSet:]: unrecognized selector sent to instance 0x4e704c0 *** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[__NSCFArray intersectsSet:]: unrecognized selector sent to instance 0x4e704c0'

So I've got two problems:

  • On the one side, I can't write a NSSet to File.
  • On the other side is my Profile class expecting an NSSet.

So I tried to create a Category of NSSet which implements writeToFile

@implementation NSSet(Persistence)

- (BOOL)writeToFile:(NSString*)path atomically:(BOOL)flag{
    NSMutableArray *temp = [NSMutableArray arrayWithCapacity:self.count];
    for(id element in self)
        [temp addObject:element];
    return [temp writeToFile:path atomically:flag];
}

+ (id)setWithContentsOfFile:(NSString *)aPath{
    return [NSSet setWithArray:[NSArray arrayWithContentsOfFile:aPath]];
}
@end

But my functions aren't called.

Is there a other way to write my NSSet or tell setValuesForKeysWithDictionary the Key "views" is a NSArray?

Or a easy Way to im-/export ManagedObjects?


Solution

  • Got problems with the nested NSDictonarys, so i said goodbye to the dynamic way. Here is my complete Solution to help others
    ViewController to call the im/export functions

    - (void) exportProfile:(Profile *)profile toPath:(NSString *)path{
        //Call the NSManagedobject function to export
        NSDictionary *profileDict = [self.selectedProfile dictionaryForExport];
    
        if([profileDict writeToFile:[path stringByStandardizingPath] atomically:YES]) 
            NSLog(@"Saved");
        else
            NSLog(@"Not saved");
    }
    
    - (void) importProfileFromPath:(NSString *)path{
        NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
        Profile *newProfile = [NSEntityDescription insertNewObjectForEntityForName:@"Profile" inManagedObjectContext:context];
    
        //load dictonary from file
        NSMutableDictionary *profileDict = [NSMutableDictionary dictionaryWithContentsOfFile:[path stringByStandardizingPath]];
        //call the NSManagedObjects import function
        [newProfile importWithDictonary:profileDict context:context];
    
        NSError *error = nil;
        if (![context save:&error]) {
    
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }
    

    NSManagedObject functions i got a hierarchy so i put them in each of my NSManagedObjects

    - (void) importWithDictonary:(NSDictionary*)dict context:(NSManagedObjectContext*)context{
        self.name = [dict objectForKey:@"name"];
    
        //Relationship
        for (NSDictionary *view in [dict objectForKey:@"views"]) {
            View *tempView = [NSEntityDescription insertNewObjectForEntityForName:@"View" inManagedObjectContext:context];
            [tempView importWithDictonary:view context:context];
            tempView.profile = self;
            [self addViewsObject:tempView];
        }
    }
    
    - (NSDictionary*) dictionaryForExport{ 
        //propertys
        NSMutableDictionary *dict = [[[self dictionaryWithValuesForKeys:[[[self entity] attributesByName] allKeys]] mutableCopy] autorelease];
        NSURL *objectID = [[self objectID] URIRepresentation];
        [dict setObject: [objectID absoluteString] forKey:@"objectID"];
        NSMutableArray *views = [NSMutableArray array];
    
        //relationship
        for (View *view in self.views) {
            [views addObject:[view dictionaryForExport]];
        }
        [dict setObject:views forKey:@"views"];
        return dict;
    }
    

    not the most beautiful solution but it works :)
    and i have still to figure out how to avoid duplicates in my n:m relationship

    Thanks