Recursive Mutable Objects

Tutorial By 6 years ago

Often when I am programming in an app that needs a data store, I will use PLists, due to their ability to be read and written to from the NSDictionary class. A problem with this is when reading from a PList all the objects are instanced as immutable unless otherwise specified, but going through an entire dictionary/array structure can be tedious even in code, so I thought it would be a good idea to make a snippet of code that people could use to just make all NSDictionaries, NSArrays and NSStrings mutable with 1 function call.

+(id) recursiveMutable:(id)object
	if([object isKindOfClass:[NSDictionary class]])
		NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithDictionary:object];
		for(NSString* key in [dict allKeys])
			[dict setObject:[App recursiveMutable:[dict objectForKey:key]] forKey:key];
		return dict;
	else if([object isKindOfClass:[NSArray class]])
		NSMutableArray* array = [NSMutableArray arrayWithArray:object];
		for(int i=0;i<[array count];i++)
			[array replaceObjectAtIndex:i withObject:[App recursiveMutable:[array objectAtIndex:i]]];
		return array;
	else if([object isKindOfClass:[NSString class]])
		return [NSMutableString stringWithString:object];
	return object;

This function basically takes either an NSString, NSDictionary or NSArray and calls itself on the object below it (in dictionaries case that would be keys) until it has called every object that the dictionary or array can contain, then returns the mutable copy of that object. Used in combination with the writeToFile and dictionaryWithContentsOfFile methods of NSDictionary it is a powerful way to store and manipulate data on the iPhone. To test this function I used the following code:

NSDictionary* testDict = [NSDictionary dictionaryWithObjectsAndKeys:[NSDictionary dictionaryWithObject:@"Test" forKey:@"Key"],@"A",[NSArray arrayWithObjects:@"1",[NSNumber numberWithInt:2],@"3",nil],@"B",@"Test String",@"C",nil];
NSMutableDictionary* testMutableDict = [App recursiveMutable:testDict];

// Test A
[[testMutableDict objectForKey:@"A"] setObject:@"Test2" forKey:@"Key2"];
[[[testMutableDict objectForKey:@"A"] objectForKey:@"Key"] appendString:@" -- This Works"];
// Test B
[[testMutableDict objectForKey:@"B"] addObject:@"4"];
// Test C
[[testMutableDict objectForKey:@"C"] appendString:@" - Just testing NSMutableString again"];
NSLog(@"testMutableDict = %@",testMutableDict);

The output from NSLog is:

testMutableDict = { A = { Key = "Test -- This Works"; Key2 = Test2; }; B = ( 1, 2, 3, 4 ); C = "Test String - Just testing NSMutableString again"; }

Showing that it does indeed work. This makes things so much easier than going through the dictionary every time making mutable copies of everything you want to change.

  • jacksctsai

    Thanks for sharing! Exactly what I need.