Re: How to clone a mutable dictionary
Re: How to clone a mutable dictionary
- Subject: Re: How to clone a mutable dictionary
- From: Jerry Krinock <email@hidden>
- Date: Fri, 24 Apr 2009 11:17:31 -0700
I spent some time on this problem a couple months ago and found some
code on cocoadev which I improved upon, also added a little test
code. There still may be bugs in it.
I don't know what the byte/character limit is on this list, but at
least the header should make it through.
-------------
#import <Cocoa/Cocoa.h>
/*!
@brief Categories for making mutable deep copies of dictionaries,
arrays and sets.
@details The original author says that this doesn't work:
"... for the life of me I can't figure out why, it seems that -copy
is always a copy of the pointers. Examining two dictionaries in the
debugger using this method shows that the objects have different
pointers but their components are identical, STILL. So it seems not
to work."
Note that another way to make a deep copy is
make an archive of it and immediately unarchive it into a
different variable. The only down-side is that the object to
be copied must implement NSCoding.
To do that,
id foo = ... ;
NSData* fooArchive = [NSKeyedArchiver
archivedDataWithRootObject:foo] ;
id fooCopy = [NSKeyedUnarchiver unarchiveObjectWithData:fooArchive] ;
Source: http://www.cocoadev.com/index.pl?
MutableDeepCopyAndUserDefaults
*/
/*!
@brief A category of NSObject which produces deep copies
of collections containing dictionaries, arrays and/or sets.
@details
*/
/*!
@brief Rule for how to clone leaf nodes when making a deep copy.
@details These are listed in order from least stringent
to most stringent.
*/
typedef NSInteger SSYCloneStyleBitmask ;
extern SSYCloneStyleBitmask const SSYCloneStyleBitmaskCopy ;
extern SSYCloneStyleBitmask const SSYCloneStyleBitmaskMutable ;
extern SSYCloneStyleBitmask const SSYCloneStyleBitmaskEncodeable ;
extern SSYCloneStyleBitmask const SSYCloneStyleBitmaskSerializable ;
@interface NSObject (DeepCloning)
/*!
@brief Returns a deep, mutable copy of the receiver
@details If an object responds to -mutableCopyWithZone and
-count, it is treated as a container node.
Leaf nodes are treated as follows:
<ul>
<li>If the style mask specifies serializable but an object is not
serializable, its image in the returned result will be its
-description.</li>
<li>Else, if the style mask specifies encodeable but an object is not
encodeable with NSKeyedArchiver, its image in the returned result
will be its -description.</li>
<li>Else, if the style mask specifies mutable and the object responds
to -mutableCopyWithZone:, its image in the returned result will be a
mutable copy of the object.</li>
<li>Else, if the style mask specifies copy and the object responds to
-copyWithZone:, its image the returned result will be a copy
of the object.</li>
<li>Else, its image in the returned result is the object itself.</li>
</ul>
@param style Determines the makeup of non-collection
objects in the result */
- mutableDeepCloneStyle:(SSYCloneStyleBitmask)style;
@end
#import "NSObject+DeepCloning.h"
SSYCloneStyleBitmask const SSYCloneStyleBitmaskCopy = 1 ;
SSYCloneStyleBitmask const SSYCloneStyleBitmaskMutable = 2 ;
SSYCloneStyleBitmask const SSYCloneStyleBitmaskEncodeable = 4 ;
SSYCloneStyleBitmask const SSYCloneStyleBitmaskSerializable = 8 ;
@implementation NSObject (DeepCloning)
- copyLeafStyle:(SSYCloneStyleBitmask)style {
if(
((style & SSYCloneStyleBitmaskSerializable) != 0)
&&
![NSPropertyListSerializationdataFromPropertyList:self
format:NSPropertyListBinaryFormat_v1_0
errorDescription:NULL]
) {
// Invoker specified serializable but self is not serializable.
// Return a description
return [[self description] retain] ;
}
else if(
((style & SSYCloneStyleBitmaskMutable) != 0)
&&
![NSKeyedArchiver archivedDataWithRootObject:self]
) {
// Invoker specified mutable and self is mutable
// Return a mutable copy
return [[self description] retain] ;
}
else if(
((style & SSYCloneStyleBitmaskCopy) != 0)
&&
[self respondsToSelector:@selector(copyWithZone:)]
) {
// Invoker specified copy and self is copyable
// Return a copy
return [self copy];
}
else {
// Return self
return [self retain];
}
}
- mutableDeepCloneStyle:(SSYCloneStyleBitmask)style {
if (
[self respondsToSelector:@selector(mutableCopyWithZone:)]
&&
[self respondsToSelector:@selector(count)]) {
return [self mutableCopy] ;
}
else {
return [self copyLeafStyle:style] ;
}
// Supress compiler warning
return nil ;
}
@end
@implementation NSDictionary (DeepCloning)
- mutableDeepCloneStyle:(SSYCloneStyleBitmask)style {
NSMutableDictionary *newDictionary = [[NSMutableDictionary alloc]
init];
for (id key in self) {
id obj = [[self objectForKey:key] mutableDeepCloneStyle:style];
[newDictionary setObject:obj forKey:key];
[obj release];
}
return newDictionary;
}
@end
@implementation NSArray (DeepCloning)
- mutableDeepCloneStyle:(SSYCloneStyleBitmask)style {
NSMutableArray *newArray = [[NSMutableArray alloc] init];
for (id object in self) {
[newArray addObject:object];
[object release];
}
return newArray;
}
@end
@implementation NSSet (DeepCloning)
- mutableDeepCloneStyle:(SSYCloneStyleBitmask)style {
NSMutableSet *newSet = [[NSMutableSet alloc] init];
for (id object in self) {
[newSet addObject:object];
[object release];
}
return newSet;
}
@end
#ifdef TEST_CODE_FOR_NSOBJECT_DEEP_CLONING
#import "NSDictionary+KeyPaths.h"
@interface Foo : NSObject {
}
@end
@implementation Foo
- (NSString*)description {
return @"This is a Foo." ;
}
@end
int main(int argc, const char *argv[]) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init] ;
NSMutableDictionary* md = [NSMutableDictionary dictionary] ;
[md setValue:@"red"
forKeyPath:@"meals.lunch.fruit.color"] ;
[md setValue:[[[Foo alloc] init] autorelease]
forKeyPath:@"meals.lunch.cheese.color"] ;
NSLog(@"original = %@", md) ;
[md serializableDictionary] ;
NSMutableDictionary* mdc = [md
mutableDeepCloneStyle:SSYCloneStyleBitmaskSerializable] ;
NSLog(@"mdc = %@", mdc) ;
[pool release] ;
return 0 ;
}
#endif
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden