Deep Copying

Yesterday, we discussed loading a (mutable) plist from disk. To review: there are built-in Cocoa functions that load plists, but they return immutable data structures. (Happily, Core Foundation functions exist that can create mutable plists from XML files.) Suppose you wanted to create mutable structures from the immutable ones returned by the Cocoa functions? The built-in mutableCopy functions only do shallow copies, so you’d have write a little code. To which we now turn.

Example

To review yesterday’s example, let’s assume you have a plist stored on disk in the the following XML file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>alpha</key>
	<array>
		<integer>0</integer>
		<integer>1</integer>
		<integer>2</integer>
	</array>
	<key>bravo</key>
	<array>
		<integer>3</integer>
		<integer>4</integer>
		<integer>5</integer>
	</array>
	<key>charlie</key>
	<array>
		<integer>6</integer>
		<integer>7</integer>
		<integer>8</integer>
	</array>
</dict>
</plist>

Let’s also assume that you load it with the following code:

// Assume that path is the pathname of a file with the XML contents shown above
NSDictionary* elements = [[NSDictionary dictionaryWithContentsOfFile:path] retain];

How can you convert elements to a deeply mutable data structure?

Categories

To perform this immutable to mutable conversion, you’ll need a set of deep copying functions. The cleanest approach is to use Objective-C’s categories to extend the NSDictionary, NSArray, NSString, NSDate, NSData, and NSNumber classes to have deepMutableCopy methods. (Since NSDate and NSNumber don’t have mutable analogs, these classes’ deepMutableCopy methods will just do simple copies; the methods are included for symmetry.)

Here’s what the code might look like. First, add a DeepCopy.h file to your project, with the category declarations:

#import <UIKit/UIKit.h>



@interface NSDictionary (DeepMutableCopy)

- (id)deepMutableCopy;

@end


@interface NSArray (DeepMutableCopy)

- (id)deepMutableCopy;

@end


@interface NSString (DeepMutableCopy)

- (id)deepMutableCopy;

@end


@interface NSDate (DeepMutableCopy)

- (id)deepMutableCopy;

@end


@interface NSData (DeepMutableCopy)

- (id)deepMutableCopy;

@end


@interface NSNumber (DeepMutableCopy)

- (id)deepMutableCopy;

@end

Then, add a DeepCopy.m file to your project, with the category definitions:

#import "DeepCopy.h"


@implementation NSDictionary (DeepMutableCopy)

- (id)deepMutableCopy
{
	NSMutableDictionary* rv = [[NSMutableDictionary alloc] initWithCapacity:[self count]];
	NSArray* keys = [self allKeys];

        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
	for (id k in keys)
	{
		[rv setObject:[[[self valueForKey:k] deepMutableCopy] autorelease] forKey:k];
	}
	[pool release];

	return rv;
}

@end


@implementation NSArray (DeepMutableCopy)

- (id)deepMutableCopy
{
	int n = [self count];
	NSMutableArray* rv = [[NSMutableArray alloc] initWithCapacity:n];
	
        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
	for (int i = 0; i < n; i++)
	{
		[rv insertObject:[[[self objectAtIndex:i] deepMutableCopy] autorelease] atIndex:i];
	}
	[pool release];
	
	return rv;
}

@end


@implementation NSString (DeepMutableCopy)

- (id)deepMutableCopy
{
	return [self mutableCopy];
}

@end


@implementation NSDate (DeepMutableCopy)

- (id)deepMutableCopy
{
	return [self copy];
}

@end


@implementation NSData (DeepMutableCopy)

- (id)deepMutableCopy
{
	return [self mutableCopy];
}

@end


@implementation NSNumber (DeepMutableCopy)

- (id)deepMutableCopy
{
	return [self copy];
}

@end

Now, you can use the deepMutableCopy method to - ah - make a deep mutable copy of elements:

#import "DeepCopy.h"
// ... snip ...
// Assume that path is the pathname of a file with the XML contents shown above
NSDictionary* elements = [[NSDictionary dictionaryWithContentsOfFile:path] deepMutableCopy];
Share and Enjoy:
  • Twitter
  • Facebook
  • Digg
  • Reddit
  • HackerNews
  • del.icio.us
  • Google Bookmarks
  • Slashdot
This entry was posted in iPhone. Bookmark the permalink.