<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Retain Count&#039;s Cocoa Braindump</title>
	<atom:link href="http://retaincount.com/blog/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://retaincount.com/blog</link>
	<description>Thoughts on Objective-C</description>
	<lastBuildDate>Wed, 01 Jul 2009 23:40:22 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Auto Archiving using the Objective-C Runtime</title>
		<link>http://retaincount.com/blog/?p=7</link>
		<comments>http://retaincount.com/blog/?p=7#comments</comments>
		<pubDate>Wed, 01 Jul 2009 16:29:04 +0000</pubDate>
		<dc:creator>retainCount</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[TPAutoArchiver]]></category>

		<guid isPermaLink="false">http://retaincount.com/blog/?p=7</guid>
		<description><![CDATA[Cocoa has a wonderful system for archiving objects: NSCoder &#38; friends. Simply implement the NSCoding protocol in your model classes, and use NSKeyedArchiver on the &#8220;root&#8221; object in your object graph. It takes care of the intricacies of managing relationships, multiple references to the same object, etc. &#8211; stuff you really don&#8217;t want to have [...]]]></description>
			<content:encoded><![CDATA[<p>Cocoa has a wonderful system for archiving objects: NSCoder &amp; friends. Simply implement the NSCoding protocol in your model classes, and use NSKeyedArchiver on the &#8220;root&#8221; object in your object graph. It takes care of the intricacies of managing relationships, multiple references to the same object, etc. &#8211; stuff you really don&#8217;t want to have to write yourself.</p>
<pre><code>
if (![NSKeyedArchiver archiveRootObject:fooBar toFile:pathToFooBar]) {
	/* handle error */
}
</code></pre>
<p>I&#8217;ve observed that many basic objects end up with an NSCoding implementation similar to this:</p>
<pre><code>- (id)initWithCoder:(NSCoder *)aCoder {
	if (self = [self init]) {
		[self setFoo:[aCoder objectForKey:TPObjectFooKey];
		[self setBar:[aCoder objectForKey:TPObjectBarKey];
		[self setBozo:[aCoder objectForKey:TPObjectBozoKey];
		[self setAh:[aCoder objectForKey:TPObjectAhKey];
		[self setEh:[aCoder objectForKey:TPObjectEhKey];
	}
	return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
	[aCoder encodeObject:[self foo] forKey:TPObjectFooKey];
	[aCoder encodeObject:[self bar] forKey:TPObjectBarKey];
	[aCoder encodeObject:[self bozo] forKey:TPObjectBozoKey];
	[aCoder encodeObject:[self ah] forKey:TPObjectAhKey];
	[aCoder encodeObject:[self eh] forKey:TPObjectEhKey];
}
</code></pre>
<p>Well, I don&#8217;t know about you, but I personally <em><strong>hate</strong></em> writing the same code over and over again. Not only is it annoying to rewrite nearly identical code for each project, it is tedious to maintain. If you add another property to your class, you must add it to both your <code>initWithCoder:/encodeWithCoder:</code> methods.</p>
<h3>The Solution</h3>
<p>Like most developers, I&#8217;m <span style="text-decoration: line-through;">efficient</span> lazy. Luckily, this repetitious piece of code is generalizable, and thus can be replaced with a helper class. Harnessing the magic of <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/">Key-Value Coding</a> and the <a href="http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html">Objective-C runtime</a>, I wrote an auto-archiver class that handles this common task.</p>
<p>It&#8217;s simple in both concept and integration (if your classes are Key-Value Coding compliant. Which they are, of course. Right? Right!?)</p>
<p>If you are using Objective-C 2.0 properties, you simply call <code>+archiveObject:withCoder:</code> in <code>-encodeWithCoder:</code>, and the corresponding <code>+unarchiveObject:withCoder:</code> in <code>-initWithCoder:</code>.</p>
<pre><code>- (id)initWithCoder:(NSCoder *)aCoder {
	if (self = [self init]) {
		[TPAutoArchiver unarchiveObject:self
				      withCoder:aCoder];
	}
	return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
	[TPAutoArchiver archiveObject:self
			    withCoder:aCoder];
}
</code></pre>
<p>If the class uses conventional mutator/accessor pairs, there is a slight bit more work involved. Your class should have the following method as well to specify what other keys you would like serialized:</p>
<pre><code>+ (NSArray *)autoArchiverKeysToAdd {
	return [NSArray arrayWithObjects:@"foo", @"bar", nil];
}
</code></pre>
<p>And of course, you can also implement <code>+autoArchiverKeysToExclude</code> if there are keys (properties included) you wish to not archive.</p>
<h3>How does it work?</h3>
<p>When TPAutoArchiver&#8217;s <code>+archiveObject:withCoder:</code> method is invoked, the object being archived&#8217;s property names are obtained (via <code>class_copyPropertyList()</code>). If the object has other keys it would like archived (or excluded), those keys are added or removed.</p>
<p>Then, the keys are passed to the NSObject method, <code>-dictionaryWithValuesForKeys:</code>, and we get their values, including non-objects (such as ints, floats, etc.).</p>
<p>Those key/value pairs are then archived under a special key that TPAutoArchiver looks for when unarchiving the object (the unarchiving process invokes <code>-setValuesForKeyWithDictionary:</code> on the object being unarchived to set the values)</p>
<h3>Download TPAutoArchiver</h3>
<p>Alright kids, that&#8217;s all for now. Feel free to contact me and send me errata, feedback, hate mail, etc. at the following address:</p>
<p><em>joshua AT retainCount DOT com</em></p>
<div class="download-bucket"><a href="http://retaincount.com/code/TPAutoArchiverSample.zip"><img style="float:left;" src="http://retaincount.com/blog/wp-content/uploads/2009/06/icon.file.zip.png" border="0" alt="icon.file.zip.png" width="128" height="128" /></a></p>
<p><a href="http://retaincount.com/code/TPAutoArchiverSample.zip">Sample Project</a></p>
<p><a href="http://retaincount.com/code/TPAutoArchiver.zip">TPAutoArchiver.m+h</a></div>
<p><em>Released under the MIT license (which means you can pretty much do whatever you want with it, provided you keep the copyright notice if you redistribute or modify the source)</em></p>
]]></content:encoded>
			<wfw:commentRss>http://retaincount.com/blog/?feed=rss2&amp;p=7</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
