Skip to content

Instantly share code, notes, and snippets.

@yfujiki
Created January 23, 2012 18:48
Show Gist options
  • Save yfujiki/1664847 to your computer and use it in GitHub Desktop.
Save yfujiki/1664847 to your computer and use it in GitHub Desktop.
Deep mutable copy category method of NSDictionary (ObjC)
- (NSMutableDictionary *) mutableDeepCopy {
NSMutableDictionary * returnDict = [[NSMutableDictionary alloc] initWithCapacity:self.count];
NSArray * keys = [self allKeys];
for(id key in keys) {
id oneValue = [self objectForKey:key];
id oneCopy = nil;
if([oneValue respondsToSelector:@selector(mutableDeepCopy)]) {
oneCopy = [oneValue mutableDeepCopy];
}
else if([oneValue respondsToSelector:@selector(mutableCopy)]) {
oneCopy = [oneValue mutableCopy];
}
else {
oneCopy = [oneValue copy];
}
[returnDict setValue:oneValue forKey:key];
}
return returnDict;
}
@wooknight
Copy link

@VasilyIvanov

Excellent catch. Solved my problem

@gentwo
Copy link

gentwo commented Jan 27, 2016

Collating all the above comments so it can be dropped in to code. Added a MutableDeepCopying protocol, so other objects can adopt it if needed.

// Header
@protocol MutableDeepCopying <NSObject>
-(id) mutableDeepCopy;
@end
@interface NSDictionary (MutableDeepCopy) <MutableDeepCopying>
@end
@interface NSArray (MutableDeepCopy) <MutableDeepCopying>
@end

// Implementation
@implementation NSDictionary (MutableDeepCopy)
- (NSMutableDictionary *) mutableDeepCopy {
  NSMutableDictionary * returnDict = [[NSMutableDictionary alloc] initWithCapacity:self.count];
  NSArray * keys = [self allKeys];
  for(id key in keys) {
    id aValue = [self objectForKey:key];
    id theCopy = nil;
    if([aValue conformsToProtocol:@protocol(MutableDeepCopying)]) {
      theCopy = [aValue mutableDeepCopy];
    } else if([aValue conformsToProtocol:@protocol(NSMutableCopying)]) {
      theCopy = [aValue mutableCopy];
    } else if([aValue conformsToProtocol:@protocol(NSCopying)]){
      theCopy = [aValue copy];
    } else {
      theCopy = aValue;
    }
    [returnDict setValue:theCopy forKey:key];
  }
  return returnDict;
}
@end

@implementation NSArray (MutableDeepCopy)
-(NSMutableArray *)mutableDeepCopy {
  NSMutableArray *returnArray = [[NSMutableArray alloc] initWithCapacity:self.count];
  for(id aValue in self) {
    id theCopy = nil;
    if([aValue conformsToProtocol:@protocol(MutableDeepCopying)]) {
      theCopy = [aValue mutableDeepCopy];
    } else if([aValue conformsToProtocol:@protocol(NSMutableCopying)]) {
      theCopy = [aValue mutableCopy];
    } else if([aValue conformsToProtocol:@protocol(NSCopying)]){
      theCopy = [aValue copy];
    } else {
      theCopy = aValue;
    }
    [returnArray addObject:theCopy];
  }
  return returnArray;
}
@end

@Motti-Shneor
Copy link

This is so nice! Could it be even nicer, to support the equivalent of mutability-options in NSPropertyListSerialization? i.e,

typedef NS_OPTIONS(NSUInteger, NSPropertyListMutabilityOptions) {
NSPropertyListImmutable = kCFPropertyListImmutable,
NSPropertyListMutableContainers = kCFPropertyListMutableContainers,
NSPropertyListMutableContainersAndLeaves = kCFPropertyListMutableContainersAndLeaves
};

so mutableDeepCopy method can receive the option, and selectively make (deep) mutable copies only to containers, but NOT to the "leaves" (e.g. NSData, NSString, NSDate, NSNumber etc. ? What's the best way to go about it?

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