• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: How to clone a mutable dictionary
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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.&nbsp;

 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


References: 
 >How to clone a mutable dictionary (From: Steve Cronin <email@hidden>)
 >Re: How to clone a mutable dictionary (From: Graham Cox <email@hidden>)
 >Re: How to clone a mutable dictionary (From: Graham Cox <email@hidden>)
 >Re: How to clone a mutable dictionary (From: Steve Cronin <email@hidden>)
 >Re: How to clone a mutable dictionary (From: Mike Abdullah <email@hidden>)
 >Re: How to clone a mutable dictionary (From: Steve Cronin <email@hidden>)

  • Prev by Date: Clicking through a NSView with CALayers
  • Next by Date: Re: WebView setDownloadDelegate: issue
  • Previous by thread: Re: How to clone a mutable dictionary
  • Next by thread: Re: How to clone a mutable dictionary
  • Index(es):
    • Date
    • Thread