- 
      
- 
        Save yfujiki/1664847 to your computer and use it in GitHub Desktop. 
| - (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; | |
| } | 
This doesn't work for all cases as all NSObject-based objects respond to mutableCopy selector. Instead, this needs to be done:
        if([oneValue respondsToSelector:@selector(mutableDeepCopy)]) {
            oneCopy = [oneValue mutableDeepCopy];
        } else if([oneValue conformsToProtocol:@protocol(NSMutableCopying)]) {
            oneCopy = [oneValue mutableCopy];
        } else if([oneValue conformsToProtocol:@protocol(NSCopying)]){
            oneCopy = [oneValue copy];
        } else {
            oneCopy = oneValue;
        }
To do the same thing for arrays:
- (NSMutableArray *)mutableDeepCopy
{
    NSMutableArray *returnArray = [[NSMutableArray alloc] initWithCapacity:self.count];
    for(id oneValue in self) {
        id oneCopy = nil;
        if([oneValue respondsToSelector:@selector(mutableDeepCopy)]) {
            oneCopy = [oneValue mutableDeepCopy];
        } else if([oneValue conformsToProtocol:@protocol(NSMutableCopying)]) {
            oneCopy = [oneValue mutableCopy];
        } else if([oneValue conformsToProtocol:@protocol(NSCopying)]){
            oneCopy = [oneValue copy];
        } else {
            oneCopy = oneValue;
        }
        [returnArray addObject:oneCopy];
    }
    return returnArray;
}
Excellent catch. Solved my problem
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
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?
Maybe you wanted to add oneCopy to returnDict, not oneValue (line 18)?