Skip to content

Instantly share code, notes, and snippets.

@vl4dimir
Created May 8, 2010 20:09
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save vl4dimir/394743 to your computer and use it in GitHub Desktop.
Save vl4dimir/394743 to your computer and use it in GitHub Desktop.
@interface ExtendedManagedObject : NSManagedObject {
BOOL traversed;
}
@property (nonatomic, assign) BOOL traversed;
- (NSDictionary*) toDictionary;
- (void) populateFromDictionary:(NSDictionary*)dict;
+ (ExtendedManagedObject*) createManagedObjectFromDictionary:(NSDictionary*)dict
inContext:(NSManagedObjectContext*)context;
@end
@implementation ExtendedManagedObject
@synthesize traversed
#pragma mark -
#pragma mark Dictionary conversion methods
- (NSDictionary*) toDictionary
{
self.traversed = YES;
NSArray* attributes = [[[self entity] attributesByName] allKeys];
NSArray* relationships = [[[self entity] relationshipsByName] allKeys];
NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:
[attributes count] + [relationships count] + 1];
[dict setObject:[[self class] description] forKey:@"class"];
for (NSString* attr in attributes) {
NSObject* value = [self valueForKey:attr];
if (value != nil) {
[dict setObject:value forKey:attr];
}
}
for (NSString* relationship in relationships) {
NSObject* value = [self valueForKey:relationship];
if ([value isKindOfClass:[NSSet class]]) {
// To-many relationship
// The core data set holds a collection of managed objects
NSSet* relatedObjects = (NSSet*) value;
// Our set holds a collection of dictionaries
NSMutableSet* dictSet = [NSMutableSet setWithCapacity:[relatedObjects count]];
for (ExtendedManagedObject* relatedObject in relatedObjects) {
if (!relatedObject.traversed) {
[dictSet addObject:[relatedObject toDictionary]];
}
}
[dict setObject:dictSet forKey:relationship];
}
else if ([value isKindOfClass:[ExtendedManagedObject class]]) {
// To-one relationship
ExtendedManagedObject* relatedObject = (ExtendedManagedObject*) value;
if (!relatedObject.traversed) {
// Call toDictionary on the referenced object and put the result back into our dictionary.
[dict setObject:[relatedObject toDictionary] forKey:relationship];
}
}
}
return dict;
}
- (void) populateFromDictionary:(NSDictionary*)dict
{
NSManagedObjectContext* context = [self managedObjectContext];
for (NSString* key in dict) {
if ([key isEqualToString:@"class"]) {
continue;
}
NSObject* value = [dict objectForKey:key];
if ([value isKindOfClass:[NSDictionary class]]) {
// This is a to-one relationship
ExtendedManagedObject* relatedObject =
[ExtendedManagedObject createManagedObjectFromDictionary:(NSDictionary*)value
inContext:context];
[self setValue:relatedObject forKey:key];
}
else if ([value isKindOfClass:[NSSet class]]) {
// This is a to-many relationship
NSSet* relatedObjectDictionaries = (NSSet*) value;
// Get a proxy set that represents the relationship, and add related objects to it.
// (Note: this is provided by Core Data)
NSMutableSet* relatedObjects = [self mutableSetValueForKey:key];
for (NSDictionary* relatedObjectDict in relatedObjectDictionaries) {
ExtendedManagedObject* relatedObject =
[ExtendedManagedObject createManagedObjectFromDictionary:relatedObjectDict
inContext:context];
[relatedObjects addObject:relatedObject];
}
}
else if (value != nil) {
// This is an attribute
[self setValue:value forKey:key];
}
}
}
+ (ExtendedManagedObject*) createManagedObjectFromDictionary:(NSDictionary*)dict
inContext:(NSManagedObjectContext*)context
{
NSString* class = [dict objectForKey:@"class"];
ExtendedManagedObject* newObject =
(ExtendedManagedObject*)[NSEntityDescription insertNewObjectForEntityForName:class
inManagedObjectContext:context];
[newObject populateFromDictionary:dict];
return newObject;
}
@end
@tonyxiao
Copy link

Can you serialize a NSArray of NSManagedObjects using this?

@vl4dimir
Copy link
Author

Sure, just loop through the NSArray and call toDictionary on each object.

@tonyxiao
Copy link

The problem is that those objects have references to each other and calling toDictionary on each object cause the whole object graph to be duplicated many times.

@vl4dimir
Copy link
Author

vl4dimir commented Feb 4, 2012

The "traversed" flag should prevent this from happening (see lines 10 and 52 in ExtendedManagedObject.m). This is a quick-and-dirty solution really, since it just ignores objects that were already traversed. I currently don't have time to redesign this, so if you think of something more robust, let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment