Dragging and dropping a Core Data object between documents is a little bit of hell. The reason for this is that they aren’t NSCoding compliant and there’s no easy way to do it because initWithCoder: doesn’t let you set the managed object context to whatever the current one is. So the solution for copying, and thus for drag and drop, has been to gather a list of properties for the object and then send that over in the drag and then decode that on the other end.

Well, I found a rather quick way of doing this, and one that’s really quite easy and keeps maintenance of the data types to copy and set completely in the model (always good). Implement a method on your model object called dictionaryRepresentation and return an NSDictionary with property list types for all your data. Ensure that the keys used in the dictionary correspond to the KVC properties of your model object. To recreate the object at the other end, insert an object of the proper type into the MOC and then use the really freaking handy NSObject method setValuesForKeysWithDictionary: and pass it that dictionary. It will then iterate over it using your KVC methods and add everything back in.

A Short Example

 – (NSDictionary*) dictionaryRepresentation
{ NSArray *list = [NSArray arrayWithObjects: "name", “comments”, @“tagNames”, nil];

NSMutableDictionary* result = [NSMutableDictionary dictionary]; NSEnumerator *enu = [list objectEnumerator]; NSString *key; while (key=[enu nextObject]) { if ([self valueForKey:key]) [result setObject:[self valueForKey:key] forKey:key]; } return result;
}

Add items to the array list for every property of your object. This should handle the great majority of items that your object handles, and for most simple objects you’re pretty much done here.

However, relationships are a little more difficult, and it really depends on how you handle that relationship as to how you’re going to do it here. In the example above there’s a key for tagNames which is an array of the names of the tags that a note has. It’s not used anywhere else, and the corresponding setTagNames: method takes that array and for every item in the array it checks to see if the current document has that tag and, if so, it uses it; otherwise it creates it and then uses it. This way tags appear to have persistence with the note, even though they don’t (it’s a 2.0 feature, before you wonder why it’s not working for you in 1.2).

Other kinds of relationships would be harder to handle. If you’re using a hierarchy with your data, you may not want to include the parent and child items, for instance. Yet, if your object has large data associated with it and you put that into another entity, you’ll want some method that will copy that as well (think of making something like a contentData/setContentData pair whose only job would be to cross the relationship and get the data from the other object, making KVC easier).

Once you have the data, you simply reconstruct it on the other side of the drag by decoding the dictionary and then…

NSManagedObject *foo =
  [NSEntityDescription insertNewObjectForEntityForName:@"Note"
     inManagedObjectContext:[self managedObjectContext]];
[foo setValuesForKeysWithDictionary:thatDictionary];

If you played your cards correctly, then even your complicated values have been reconstructed, all the logic is in the model, and you have just one place to update all of your object-copying code once again. Voila.

Criticize my approach in the comments, if you must. I’m all about free advice, be it the giving or the receiving thereof.

Comment viewing options
Select your preferred way to display the comments and click "Save settings" to activate your changes.
Submitted by bewebste on November 18, 2006 - 9:50pm.

To make it even easier, there is also a method called dictionaryWithValuesForKeys: which will do essentially the same thing the loop in the example code does, with the exception that nil values are replaced with NSNulls. But, setValuesForKeysWithDictionary: will translate the NSNulls back to nils, so the end effect should be about the same.

Submitted by Adam Knight on November 18, 2006 - 10:21pm.

Oooo, pretty. Never saw that, curiously. Yeah, that’ll do it, too. Then you just maintain the list and the methods for non-plist types.

Comment viewing options
Select your preferred way to display the comments and click "Save settings" to activate your changes.
User login