Reputation: 23715
I have an NSDictionary
that contains instances of many different types objects (NSArrays
, NSDictionaries
, NSStrings
, NSNumbers
, etc...). Many of the NSDictionaries
and NSStrings
have their own nested NSDictionaries
and NSArrays
.
How can I loop through the entire hierarchy, from top to bottom, and convert ALL instances of NSDictionaries
and NSArrays
to NSMutableDictionaries
and NSMutableArrays
, respectively?
Is there any easy "recursively make mutable copies" function I'm unaware of? If not, do I just need to loop and type check repeatedly? Can I just replace as I go or do I have rebuild the entire hierarchy?
Upvotes: 8
Views: 2745
Reputation: 52592
If you used some operating system method to create the dictionary: These methods often have a parameter that allows you to create mutable objects. For example, the JSON serialiser class has flags to make all dictionaries and arrays mutable, and to make all NSString objects mutable (NSNumber and NSNull are never mutable).
Upvotes: 1
Reputation: 539945
The following method creates a nested (deep) mutable copy of nested arrays, dictionaries and sets. It can also be used to create mutable copies of non-collection objects inside the hierarchy, such as strings.
@interface NSObject (MyDeepCopy)
-(id)deepMutableCopy;
@end
@implementation NSObject (MyDeepCopy)
-(id)deepMutableCopy
{
if ([self isKindOfClass:[NSArray class]]) {
NSArray *oldArray = (NSArray *)self;
NSMutableArray *newArray = [NSMutableArray array];
for (id obj in oldArray) {
[newArray addObject:[obj deepMutableCopy]];
}
return newArray;
} else if ([self isKindOfClass:[NSDictionary class]]) {
NSDictionary *oldDict = (NSDictionary *)self;
NSMutableDictionary *newDict = [NSMutableDictionary dictionary];
for (id obj in oldDict) {
[newDict setObject:[oldDict[obj] deepMutableCopy] forKey:obj];
}
return newDict;
} else if ([self isKindOfClass:[NSSet class]]) {
NSSet *oldSet = (NSSet *)self;
NSMutableSet *newSet = [NSMutableSet set];
for (id obj in oldSet) {
[newSet addObject:[obj deepMutableCopy]];
}
return newSet;
#if MAKE_MUTABLE_COPIES_OF_NONCOLLECTION_OBJECTS
} else if ([self conformsToProtocol:@protocol(NSMutableCopying)]) {
// e.g. NSString
return [self mutableCopy];
} else if ([self conformsToProtocol:@protocol(NSCopying)]) {
// e.g. NSNumber
return [self copy];
#endif
} else {
return self;
}
}
@end
Use it like
NSDictionary *dict = ...;
NSMutableDictionary *mdict = [dict deepMutableCopy];
(Dictionary keys are not copied, only the values).
I am quite sure that I have seen something like this on SO, but cannot find it right now.
Upvotes: 18
Reputation: 162722
While Anoop's answer is just fine (I think, I didn't compile it either), if your hierarchy of instances is actually a property list, then you can use NSPropertyListSerialization to deserialize a plist with mutable containers and/or leaf nodes.
This would reduce to fewer lines of code and likely be faster than a manual descent through the object graph, but this solution only really makes sense if you are initially deserializing the plist from somewhere.
Upvotes: 2
Reputation: 46543
For the outer NSDictionary, this will create for 1-level down.
You need to call this in a method, and go on to get all dict
and array
.
NSMutableDictionary *dict=[NSMutableDictionary new];
NSMutableArray *array=[NSMutableArray new];
for(NSDictionary *dict in yourMainDictionary){
if([outerDict[dict] class]==[NSDictionary class]){
[dict setObject:outerDict[dict] forKey:dict];
}
else if([outerDict[dict] class]==[NSArray class]){
array[array.count]=outerDict[dict];
}
}
Not compiler checked. Read as algorithm
Upvotes: 1