-
-
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)?