<?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>Eschatology</title>
	<atom:link href="http://eschatologist.net/blog/?feed=rss2&#038;p=178" rel="self" type="application/rss+xml" />
	<link>http://eschatologist.net/blog</link>
	<description>Ask me how it ends…</description>
	<lastBuildDate>Mon, 29 Apr 2013 19:15:36 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Sad&#8230;</title>
		<link>http://eschatologist.net/blog/?p=250</link>
		<comments>http://eschatologist.net/blog/?p=250#comments</comments>
		<pubDate>Sun, 17 Jan 2010 11:54:17 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Life]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=250</guid>
		<description><![CDATA[Cupertino is at one edge of the Santa Clara Valley, one of the best places on the continent to grow fruit. This display is in our Whole Foods, one of the (if not the) largest stores they have. All of the brands are local and don&#8217;t exist any more, because we paved them over in [...]]]></description>
				<content:encoded><![CDATA[<p><img style="padding:0px 10px 10px 10px;" src="http://eschatologist.net/blog/wp-content/uploads/2010/01/image1384260977.jpg" width ="280" align="left" alt="image1384260977.jpg" title="image1384260977.jpg" /></p>

<p>Cupertino is at one edge of the Santa Clara Valley, one of the best places on the continent to grow fruit.</p>

<p>This display is in our Whole Foods, one of the (if not the) largest stores they have. All of the brands are local and don&#8217;t exist any more, because we paved them over in favor of single-family homes and office parks and fucking <em>lawns</em>.</p>

<p>It&#8217;s really sad, and would have been easy to avoid, too, by building <strong>up</strong> instead of <strong>out</strong>. Instead, there are always new ballot measures in Cupertino to try to limit the &#8220;scale&#8221; of building &#8211; in other words, to prevent building up &#8211; and ensure the sprawl stays. And I expect that applies to the rest of the Santa Clara Valley as well, and a huge percentage of the United States as a whole, everywhere a &#8220;subdivision&#8221; has replaced farmland.</p>

<p>Even if we could build high-rise apartments and offices, it&#8217;s not certain that the land we&#8217;ve covered with little shitbox houses, chemically-maintained lawns, and asphalt could even be used for agriculture again. The land may well be &#8220;used up&#8221; and require extensive rehabilitation to even support parkland, much less farming.</p>

<p>Someday people will look back on this as a monumental disaster, an utter failure of urban planning ands demonstration of our society&#8217;s lack of any capacity for forethought. Probably once all of humanity is facing permanent food and water shortages, later this century.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=250</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Milestone</title>
		<link>http://eschatologist.net/blog/?p=243</link>
		<comments>http://eschatologist.net/blog/?p=243#comments</comments>
		<pubDate>Sat, 09 Jan 2010 18:17:04 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[car]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=243</guid>
		<description><![CDATA[I&#8217;ve had my car for 10 years, and my odometer rolled over 100,000 miles earlier today. Time to start thinking about a new car! Maybe a Tesla Model S, in a couple of years&#8230;]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve had my car for 10 years, and my odometer rolled over 100,000 miles earlier today.</p>

<p>Time to start thinking about a new car! Maybe a <a href="http://www.teslamotors.com/models/">Tesla Model S</a>, in a couple of years&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=243</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>When to use NSOperation vs. GCD</title>
		<link>http://eschatologist.net/blog/?p=232</link>
		<comments>http://eschatologist.net/blog/?p=232#comments</comments>
		<pubDate>Wed, 09 Sep 2009 03:50:42 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[concurrency]]></category>
		<category><![CDATA[Grand Central Dispatch]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[NSOperation]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[Snow Leopard]]></category>
		<category><![CDATA[threads]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=232</guid>
		<description><![CDATA[Mac OS X has a number of concurrency mechanisms, and that increases with Snow Leopard. In addition to run loops, threads (both Cocoa and POSIX) and operations, Snow Leopard adds Grand Central Dispatch (GCD), a very lightweight way to represent units of work and the style of concurrency they need, and have the system figure [...]]]></description>
				<content:encoded><![CDATA[<p>Mac OS X has a number of concurrency mechanisms, and that increases with Snow Leopard.  In addition to run loops, threads (both Cocoa and POSIX) and operations, Snow Leopard adds <strong>Grand Central Dispatch</strong> (GCD), a very lightweight way to represent units of work and the style of concurrency they need, and have the system figure out how to schedule them.</p>

<p>But wait, don&#8217;t we have that already in NSOperation?  It shouldn&#8217;t surprise you in the least to learn that NSOperation, on Snow Leopard, is built atop GCD.  However, there are a number of differences between the two, and for that reason people have started to ask “How should I decide which to use when?”</p>

<p>The straightforward answer is a general guideline for all application development:</p>

<blockquote>
  <p><strong>Always use the highest-level abstraction available to you, and drop down to lower-level abstractions when measurement shows that they are needed.</strong></p>
</blockquote>

<p>In this particular case, it means that when writing Cocoa applications, you should generally be using NSOperation rather than using GCD directly.  Not because of a difference in efficiency, but because NSOperation provides a <em>higher-level abstraction</em> atop the mechanisms of GCD.</p>

<p>For example, you can set up a dependency between two NSOperations such that the second will only be run after the first is complete — even if they&#8217;re run on different queues.  You can use KVO to observe the completion (or cancellation) of different operations — and you can create operations that support being cancelled in the first place.  You can set a completion block to run after an application has finished.  And you can, of course, create operations from blocks using <em>NSBlockOperation</em>.</p>

<p>You&#8217;ll also fit in better with Cocoa by using NSOperation in your high-level code.  If you take a look at new Snow Leopard API on NSNotificationCenter, you&#8217;ll see one where you specify the NSOperationQueue on which you wish a notification to run a block.</p>

<p>Ultimately, you spend a little bit of overhead to use NSOperation instead of GCD, but you gain significant additional functionality that will be useful as you start to compose operations together.  And that&#8217;s the biggest benefit of NSOperation: You can break up your application in terms of units of work that can not only be run on a queue, but also canceled, observed, and depended upon.  This lets you easily define your data dependencies and ensure that you aren&#8217;t simply running code serially as a side-effect of locking.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=232</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Welcome to Snow Leopard!</title>
		<link>http://eschatologist.net/blog/?p=230</link>
		<comments>http://eschatologist.net/blog/?p=230#comments</comments>
		<pubDate>Mon, 07 Sep 2009 04:35:48 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Instruments]]></category>
		<category><![CDATA[Interface Builder]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Snow Leopard]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=230</guid>
		<description><![CDATA[Last week, Mac OS X 10.6 Snow Leopard was released! Snow Leopard represents a lot of hard work by a lot of folks at Apple and at seeded third-party developers, and it really shows. Now that it&#8217;s shipped, I can actually talk about some of the especially cool things this release has for developers.]]></description>
				<content:encoded><![CDATA[<p>Last week, Mac OS X 10.6 Snow Leopard was released!</p>

<p>Snow Leopard represents a lot of hard work by a lot of folks at Apple and at seeded third-party developers, and it really shows.</p>

<p>Now that it&#8217;s shipped, I can actually talk about some of the especially cool things this release has for developers.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=230</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Rebutting Big Nerd Ranch on Objective-C 2.0 dot notation</title>
		<link>http://eschatologist.net/blog/?p=226</link>
		<comments>http://eschatologist.net/blog/?p=226#comments</comments>
		<pubDate>Sat, 08 Aug 2009 01:47:52 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[OOP]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=226</guid>
		<description><![CDATA[The Big Nerd Ranch weblog has a new post about Objective-C 2.0 dot notation. They advocate never using it and they&#8217;re completely wrong. Given my reaction on Twitter, several people have asked me to write a more in-depth rebuttal. I&#8217;ve already addressed when and why you should use Objective-C 2.0 properties and dot notation in [...]]]></description>
				<content:encoded><![CDATA[<p>The <a href="http://weblog.bignerdranch.com/">Big Nerd Ranch weblog</a> has <a href="http://weblog.bignerdranch.com/?p=83">a new post about Objective-C 2.0 dot notation</a>.  They advocate <em>never using it</em> and they&#8217;re <em>completely wrong</em>.</p>

<p>Given <a href="https://twitter.com/eschaton/status/3175342818">my reaction on Twitter</a>, several people have asked me to write a more in-depth rebuttal.</p>

<p>I&#8217;ve already addressed <a href="http://eschatologist.net/blog/?p=160">when and why you <strong>should</strong> use Objective-C 2.0 properties and dot notation</a> in an earlier post, so I won&#8217;t go into that here.  I&#8217;ll just repeat my response to their weblog.</p>

<p>Here&#8217;s what I wrote in response:</p>

<blockquote>
  <p>I disagree most emphatically. The whole point of dot notation is that, when combined with properties, it’s not <em>just</em> an alternative syntax for invoking methods. In fact, if that’s how you think about dot syntax, STOP. That’s not what it’s for at all.</p>
  
  <p>What dot syntax and property declarations are for is separating object <em>state</em> from object <em>behavior</em>. Classical OOP only really defines objects as only exposing behavior but the past 30+ years have demonstrated rather aptly that objects consist of both. C# was actually pioneering in this; its concept of properties is rather similar to what the combination of property declarations and dot syntax enable in Objective-C.</p>
  
  <p>To write idiomatic Objective-C 2.0 you should use <code>@property</code> to declare properties, and use dot syntax to access them. Period. Doing otherwise is a bad idea because it will create code that isn’t intention-revealing to other experienced Objective-C 2.0 developers. Teaching students to do otherwise is doing them a disservice, because you’re directly contradicting those responsible for the language and its evolution.</p>
</blockquote>

<p>In short, Objective-C 2.0 has properties and dot notation as another way of expressing intent in your code.  Use them for that, don&#8217;t refuse to use them just because they weren&#8217;t in earlier versions of the language, or because they require teaching another concept.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=226</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Using &#8220;en&#8221; instead of &#8220;English&#8221; for your Xcode project&#8217;s development region</title>
		<link>http://eschatologist.net/blog/?p=224</link>
		<comments>http://eschatologist.net/blog/?p=224#comments</comments>
		<pubDate>Fri, 07 Aug 2009 03:29:02 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Interface Builder]]></category>
		<category><![CDATA[localization]]></category>
		<category><![CDATA[project model]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=224</guid>
		<description><![CDATA[Various pieces of Mac OS X and iPhone documentation have said for quite a while that the &#8220;preferred&#8221; method is now to use ISO-639-1 (two-letter) or ISO-639-2 (three-letter) language codes codes for localization purposes. Out of the box, Xcode&#8217;s project templates still use &#8220;English&#8221; rather than &#8220;en&#8221; as their default localization. How can you use [...]]]></description>
				<content:encoded><![CDATA[<p>Various pieces of Mac OS X and iPhone documentation have said for quite a while that the &#8220;preferred&#8221; method is now to use ISO-639-1 (two-letter) or ISO-639-2 (three-letter) language codes codes for localization purposes.  Out of the box, Xcode&#8217;s project templates still use &#8220;English&#8221; rather than &#8220;en&#8221; as their default localization.</p>

<p>How can you use the ISO-639 language codes everywhere in your project, rather than in just your non-English localizations?</p>

<p>It&#8217;s pretty straightforward, but it does require hand-editing of your Xcode project file.  This means that before doing anything else, you <strong>must quit Xcode and Interface Builder</strong>.</p>

<p>The first step is to rename your existing localizable resource directories <em>on disk</em> from <code>English.lproj</code> to <code>en.lproj</code>.  You can do it at the Terminal or in the Finder.  If you&#8217;re using an SCM system such as Subversion, use it to do the renaming so it preserves your file history and such as well.</p>

<p>The next step is to adjust how your existing localizable resources are referenced in your Xcode project file.  Open the <code>project.pbxproj</code> file inside your Xcode project in a plain text editor such as TextEdit (rather than Xcode) and replace <strong>all but one</strong> occurrences of the string <code>English</code> with the string <code>en</code>.  The one you don&#8217;t want to replace is in a property under the PBXProject section named <code>knownRegions</code>: This is an array of localizations Xcode knows about.  Just make sure <code>en</code> is at the end of the array:</p>

<pre><code>knownRegions = (
    English,
    Japanese,
    French,
    German,
    en,
);
</code></pre>

<p>At this point, this should be the only place <code>English</code> appears in your <code>project.pbxproj</code> file.</p>

<p>Finally — and this is the important step, and non-discoverable step — you need to <strong>add a property</strong> to the <code>project.pbxproj</code> file to tell Xcode what the Development Region for your project is.  Again, this gets put into the PBXProject section before the <code>knownRegions</code> key from above (Xcode will alphabetize the keys when saving your project for you); it should look like this:</p>

<pre><code>developmentRegion = en;
</code></pre>

<p>The default value of this key within Xcode is <code>English</code> and Xcode won&#8217;t write the key into the project if the default isn&#8217;t changed. However, there&#8217;s no user interface within Xcode for actually changing this property, making it non-discoverable.  Furthermore, if you are changing your project to use <code>en</code> as its default localization, and you <em>don&#8217;t</em> change this property, you won&#8217;t be able to add new localizations by inspecting your resources.  (This is a known issue.)</p>

<p>At this point, you can save your modified <code>project.pbxproj</code> file and open your project again in Xcode.  There&#8217;s one more thing you&#8217;ll have to change, this time in your product&#8217;s Info.plist file (or your products&#8217; Info.plist files), before you can get back to work:  You need to change the <code>CFBundleDevelopmentRegion</code> property to <code>en</code> rather than <code>English</code>.</p>

<p>Once you&#8217;ve made that change, you should safely be able to use your Xcode project normally, adding localized variants of your resources, building and running, and so on, and everything should Just Work —  now using modern ISO language codes instead of the English language names!</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=224</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Unit testing Cocoa user interfaces: Use Check Methods</title>
		<link>http://eschatologist.net/blog/?p=205</link>
		<comments>http://eschatologist.net/blog/?p=205#comments</comments>
		<pubDate>Mon, 06 Jul 2009 00:22:16 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[agile development]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Cocoa bindings]]></category>
		<category><![CDATA[human interface design]]></category>
		<category><![CDATA[Interface Builder]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[patterns]]></category>
		<category><![CDATA[test-driven development]]></category>
		<category><![CDATA[unit testing]]></category>
		<category><![CDATA[user interface testing]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=205</guid>
		<description><![CDATA[In the past, I&#8217;ve talked about ways to easily write unit tests for Cocoa applications, including tests for user interfaces using target-action and tests for interfaces using Cocoa bindings. There are some strategies you can apply to make writing tests for Cocoa code even easier, though. They&#8217;re just straightforward object-oriented programming, but sometimes we can [...]]]></description>
				<content:encoded><![CDATA[<p>In the past, I&#8217;ve talked about ways to easily write unit tests for Cocoa applications, including <a href="http://eschatologist.net/blog/?p=10" title="Unit testing Cocoa user interfaces: Target-Action">tests for user interfaces using target-action</a> and <a href="http://eschatologist.net/blog/?p=12" title="Unit testing Cocoa user interfaces: Cocoa Bindings">tests for interfaces using Cocoa bindings</a>.  There are some strategies you can apply to make writing tests for Cocoa code even easier, though.  They&#8217;re just straightforward object-oriented programming, but sometimes we can forget that all the techniques you might use in your main code base can also be applied to our test code.</p>

<p>So here&#8217;s one trick that you can use in writing tests for Cocoa user interfaces, especially in ways that will make test-driven development easier.</p>

<h3>Use a Common Base Class with Check Methods</h3>

<p>The first, probably most important thing to do is <em>use your own common base class</em> for your tests.  Don&#8217;t derive your tests directly from <code>SenTestCase</code>; instead, derive them from your own <code>MyTestCase</code> class that in turn derives from <code>SenTestCase</code>.  This gives you a place to put all of the customization that&#8217;s appropriate for your project.</p>

<p>Sometimes you might need a series of assertions to verify some particular state.  However, that series of assertions will be the same every time you need to verify that state.  Or the assertions themselves aren&#8217;t very <em>intention revealing</em> so you always wind up putting a comment above them describing what they&#8217;re really doing.</p>

<h3>Checking Target-Action</h3>

<p>A simple example of this is checking a target-action connection in a user interface.  Say you have a view controller that presents a collection of objects managed by an array controller.  Its view has an Add button that should send <code>-addObject:</code> to the array controller.  You might write a test for it like this:</p>

<pre><code>- (void)testAddButtonSendsAddObjectToArrayController {
    STAssertEquals([viewController.addButton target], viewController.arrayController,
        @"The Add button should target the array controller.");
    STAssertEquals([viewController.addButton action], @selector(addObject:),
        @"The Add button should send the -addObject: action.");
}
</code></pre>

<p>That&#8217;s not too difficult to understand, but it could be made simpler — it could be done in a single assertion.  You&#8217;d just write a method to check both the target and action at once and then use that method from your test, like this:</p>

<pre><code>// in your test base class...

/*! Tells whether the control sends the action to the target. */
- (BOOL)checkControl:(NSControl *)control
         sendsAction:(SEL)action
            toTarget:(id)target
{
    return ([control action] == action)
        &amp;&amp; ([control target] == target);
}

// in the tests specifying the view controller's behavior...

- (void)testAddButtonSendsAddObjectToArrayController {
    STAssertTrue([self checkControl:viewController.addButton
                        sendsAction:@selector(addObject:)
                           toTarget:viewController.arrayController],
        @"The Add button's action should send -addObject: to the array controller.");
}
</code></pre>

<p>That makes the intention behind the entire test a lot clearer, and it makes writing the test easier  &amp; safer since you can&#8217;t (say) forget to check either the target or the action.</p>

<p>It <em>does</em> lose a tiny bit of information:  If the test fails, you&#8217;ll have to look at your xib file instead of the failure message to determine whether it&#8217;s because the target or the action isn&#8217;t set as you&#8217;ve specified.  However, the trade-off in making the test easier to read and write is worth it here.</p>

<h3>Checking Outlets</h3>

<p>This is even worthwhile for single assertions, such as those you&#8217;d use to test that your outlets are connected in the first place.  For example, you might initially write a test that your view controller is your table view&#8217;s delegate like this:</p>

<pre><code>- (void)testViewControllerIsTableViewDelegate {
    STAssertEquals([viewController.tableView delegate], viewController,
        @"The table view's delegate should be the view controller.");
}
</code></pre>

<p>Rewriting it to be more intention-revealing with a simple check method would make it look like this:</p>

<pre><code>// in your test base class...

/*! Tells whether the outlet is connected to the given destination. */
- (BOOL)checkOutlet:(id)outlet connectsTo:(id)destination {
    return outlet == destination;
}

// in the tests specifying the view controller's behavior...

- (void)testViewControllerIsTableViewDelegate {
    STAssertTrue([self checkOutlet:[viewController.tableView delegate]
                        connectsTo:viewController],
        @"The table view's delegate should be the view controller.");
}
</code></pre>

<p>You&#8217;re not saving any code by writing your test this way — you&#8217;re actually writing more — but its <em>complexity</em> has gone down because it requires less effort to see what it&#8217;s actually trying to do.</p>

<h3>Checking Bindings</h3>

<p>This is even worthwhile in situations where you may still need a few extra assertions.  For example, Cocoa bindings are specified using a lot more information than just outlets and target-acton connections; you won&#8217;t always want to check (and specify the value of) all of it, but you can easily make the common parts clearer.</p>

<p>Going back to our Add button example, as is typical its enabled state should be bound to the array controller&#8217;s <code>canAdd</code> property.  Writing a test to specify this involves using <code>-infoForBinding:</code> and interpreting the results, which takes a couple lines of code and a couple of assertions:</p>

<pre><code>- (void)testAddButtonEnabledStateIsBoundToArrayControllerCanAdd {
    NSDictionary *bindingInfo = [viewController.addButton infoForBinding:NSEnabledBinding];
    STAssertNotNil(bindingInfo,
        @"The Add button's enabled state should be bound.");

    id observedObject = [bindingInfo objectForKey:NSObservedObjectKey];
    STAssertEquals(observedObject, viewController.arrayController,
        @"The Add button's enabled state should be bound to the array controller.");

    NSString *observedKeyPath = [bindingInfo objectForKey:NSObservedKeyPathKey];
    STAssertEqualObjects(observedKeyPath, @"canAdd",
        @"The Add button's enabled state should be bound through the 'canAdd' key path.");
}
</code></pre>

<p>This isn&#8217;t too complicated, but it does start to get tedious, especially given that you have to remember to distinguish between <code>STAssertEquals</code> (pointer equality) and <code>STAssertEqualObjects</code> (object equivalence).  Let&#8217;s put the tedium in one place:</p>

<pre><code>/*! Tells whether the object's binding is connected through the given key path. */
- (BOOL)checkObject:(id)source
         hasBinding:(NSString *)binding
           toObject:(id)destination
            through:(NSString *)keyPath
{
    NSDictionary *bindingInfo = [source infoForBinding:binding];
    id observedObject = [bindingInfo objectForKey:NSObservedObjectKey];
    NSString *observedKeyPath = [bindingInfo objectForKey:NSObservedKeyPathKey];

    return (bindingInfo != nil)
        &amp;&amp; (observedObject == destination)
        &amp;&amp; [keyPath isEqualToString:observedKeyPath];
}

// in the tests specifying the view controller's behavior...

- (void)testAddButtonEnabledStateIsBoundToArrayControllerCanAdd {
    STAssertTrue([self checkObject:viewController.addButton
                        hasBinding:NSEnabledBinding
                          toObject:viewController.arrayController
                           through:@"canAdd"],
        @"The Add button's enabled state should be bound to the array controller's 'canAdd' property.");
}
</code></pre>

<p>Much clearer!</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=205</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Objective-C 2.0 properties and to-many relationships</title>
		<link>http://eschatologist.net/blog/?p=189</link>
		<comments>http://eschatologist.net/blog/?p=189#comments</comments>
		<pubDate>Sun, 28 Jun 2009 02:28:52 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Cocoa bindings]]></category>
		<category><![CDATA[Core Data]]></category>
		<category><![CDATA[Key-Value Coding]]></category>
		<category><![CDATA[Key-Value Observing]]></category>
		<category><![CDATA[Objective-C]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=189</guid>
		<description><![CDATA[I&#8217;ve occasionally been asked about the appropriate form for properties representing to-many relationships in Objective-C 2.0. Let&#8217;s start with the example of a recipe and its ingredients, represented by instances of the Recipe and Ingredient classes. @interface Recipe : NSObject { @private NSMutableSet *_ingredients; } @property (copy) NSSet *ingredients; @end This is a pretty straightforward [...]]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve occasionally been asked about the appropriate form for properties representing to-many relationships in Objective-C 2.0.</p>

<p>Let&#8217;s start with the example of a recipe and its ingredients, represented by instances of the Recipe and Ingredient classes.</p>

<pre><code>@interface Recipe : NSObject {
@private
    NSMutableSet *_ingredients;
}

@property (copy) NSSet *ingredients;

@end
</code></pre>

<p>This is a pretty straightforward interface for the Recipe class, but how should we actually implement it?  You might first think of writing something like this:</p>

<pre><code>@implementation Recipe

- (id)init {
    if (self = [super init]) {
        _ingredients = [[NSMutableSet alloc] init];
    }
    return self;
}

- (void)dealloc {
    [_ingredients release];
    [super dealloc];
}

@synthesize ingredients = _ingredients;

@end
</code></pre>

<p>However, this <strong>will not</strong> do what you expect.  In particular, whenever you manipulate the <code>ingredients</code> property, it always <strong>replace the value</strong> of the <code>_ingredients</code> instance variable used for its storage with a new, immutable NSSet!</p>

<p>What&#8217;s wrong with this?  For one thing, you won&#8217;t be able to make any finer-grained changes to the <code>ingredients</code> property, so your code may wind up doing a lot of work unnecessarily.  You&#8217;ll only ever post Key-Value Observing changes for the entire property, as well, not for individual manipulations; anything observing those changes will probably wind up doing extra work, too.</p>

<p>Why not instead change the type of the property itself to <code>NSMutableSet *</code> then?  That way, your code could just manipulate the ingredients of a recipe directly, right?  You <em>could</em> do that, but then you wouldn&#8217;t get <strong>any</strong> Key-Value Observing notifications for changes to the property.  Why not?  Because KVO is all about notification of <strong>property</strong> changes, and changing the object that stores a property&#8217;s data isn&#8217;t the same thing as changing the property itself.</p>

<p>What should you do then?  Here&#8217;s how I would implement the <code>Recipe.ingredients</code> property instead of using the above <code>@synthesize</code> directive:</p>

<pre><code>@implementation Recipe (IngredientsProperty)

- (void)setIngredients:(NSSet *)value {
    [_ingredients setSet:value];
}

- (NSSet *)ingredients {
    return [NSSet setWithSet:_ingredients];
}

@end
</code></pre>

<p>What&#8217;s different here is that I&#8217;m taking advantage of the fact that the instance variable backing the property is mutable.  For just a getter and a setter, that isn&#8217;t a big deal.  However, since I&#8217;m dealing with a to-many relationship, I wouldn&#8217;t just write a getter and a setter.  I&#8217;d also write some of the additional relationship-KVC methods for the property, so I can manipulate the property more efficiently, and get finer-grained KVO notifications:</p>

<pre><code>@interface Recipe (IngredientsProperty)

- (void)addIngredientsObject:(Ingredient *)ingredient;
- (void)removeIngredientsObject:(Ingredient *)ingredient;

- (void)addIngredients:(NSSet *)ingredients;
- (void)removeIngredients:(NSet *)ingredients;

@end

@implementation Recipe (IngredientsProperty)

- (void)addIngredientsObject:(Ingredient *)ingredient {
    [_ingredients addObject:ingredient];
}

- (void)removeIngredientsObject:(Ingredient *)ingredient {
    [_ingredients removeObject:ingredient];
}

- (void)addIngredients:(NSSet *)ingredients {
    [_ingredients unionSet:ingredients];
}

- (void)removeIngredients:(NSSet *)ingredients {
    [_ingredients minusSet:ingredients];
}

@end
</code></pre>

<p>By doing this, when I need to manipulate a Recipe&#8217;s <code>ingredients</code> property I can use <code>-mutableSetValueForKey:</code> to do so and any changes I make will be efficient.  For example, if I&#8217;m creating a Recipe to represent <a href="http://www.jighexadecimal.com/?p=54">Meghan&#8217;s Butternut Squash Panang Curry</a>, I might write some code like this:</p>

<pre><code>NSMutableSet *ingredients = [panangCurryRecipe mutableSetValueForKey:@"ingredients"];

[ingredients addObject:[Ingredient ingredientWithName:@"Butternut Squash" quantity:1]];
[ingredients addObject:[Ingredient ingredientWithName:@"Panang Curry Paste" quantity:1]];
[ingredients addObject:[Ingredient ingredientWithName:@"Coconut Milk" quantity:1]];
</code></pre>

<p>Instead of making several copies of the set as I make changes, the underlying mutable set is changed in as efficient a way as possible given the accessors I&#8217;ve implemented.  I don&#8217;t have to do any extra work to make that happen.</p>

<p>I also get efficient KVO change notifications for the property, so if I have any user interface bound to it — whether through Cocoa bindings or, if I&#8217;m using Cocoa Touch, a &#8220;bindings lite&#8221; implemented atop KVO — the change notifications it receives will reflect exactly the changes made, instead of wholesale replacement of the set.</p>

<p>I could still improve the code above.  I&#8217;m using <code>-[NSObject(NSKeyValueCoding) mutableSetValueForKey:]</code> to manipulate the <code>Recipe.ingredients</code> property.  That means I don&#8217;t get nice Code Sense completion from Xcode, and have to remember the property&#8217;s name <em>and</em> spell it correctly when I use it in a string.  So I&#8217;ll add the following property declaration and implementation:</p>

<pre><code>@interface Recipe (IngredientsProperty)
@property (readonly, copy) NSMutableSet *mutableIngredients;
@end

@implementation Recipe (IngredientsProperty)

- (NSMutableSet *)mutableIngredients {
    return [self mutableSetValueForKey:@"ingredients"];
}

@end
</code></pre>

<p>You&#8217;re probably thinking something like &#8220;Wait a minute, <code>readonly</code> and <code>NSMutableSet</code>?!&#8221;  That&#8217;s exactly what I mean to say, though:  You can mutate the <em>collection</em> you get back (&#8220;read&#8221;) from the property, but not the <em>property itself</em>.</p>

<blockquote>
  <p><strong>Update:</strong> On Twitter, a couple of people asked why I didn&#8217;t just use <code>-[Recipe addIngredientsObject:]</code> directly, since I have that available.  I certainly could have done that, and it&#8217;d have all of the advantages I cite, and it wouldn&#8217;t require the creation of the proxy mutable set either.  However, if I wanted to something more complex than just an addition, using the proxy mutable set is a significant advantage.</p>
  
  <p>This is because the proxy mutable set (or array, if you&#8217;re using an ordered relationship and <code>-mutableArrayValueForKey:</code>) will do the heavy lifting of figuring out the right combination of the accessors your implemented accessors to perform an operation most efficiently.  Also, technologies like Cocoa bindings will always use the proxy.</p>
</blockquote>

<p>With this additional property in place, the entire Recipe class will look something like this:</p>

<pre><code>@interface Recipe : NSObject {
@private
    NSMutableSet *_ingredients;
}

@property (copy) NSSet *ingredients;
@property (readonly, copy) NSMutableSet *mutableIngredients;

- (void)addIngredientsObject:(Ingredient *)ingredient;
- (void)removeIngredientsObject:(Ingredient *)ingredient;

- (void)addIngredients:(NSSet *)ingredients;
- (void)removeIngredients:(NSet *)ingredients;

@end

@implementation Recipe

- (id)init {
    if (self = [super init]) {
        _ingredients = [[NSMutableSet alloc] init];
    }
    return self;
}

- (void)dealloc {
    [_ingredients release];
    [super dealloc];
}

- (void)setIngredients:(NSSet *)value {
    [_ingredients setSet:value];
}

- (NSSet *)ingredients {
    return [NSSet setWithSet:_ingredients];
}

- (NSMutableSet *)mutableIngredients {
    return [self mutableSetValueForKey:@"ingredients"];
}

- (void)addIngredientsObject:(Ingredient *)ingredient {
    [_ingredients addObject:ingredient];
}

- (void)removeIngredientsObject:(Ingredient *)ingredient {
    [_ingredients removeObject:ingredient];
}

- (void)addIngredients:(NSSet *)ingredients {
    [_ingredients unionSet:ingredients];
}

- (void)removeIngredients:(NSSet *)ingredients {
    [_ingredients minusSet:ingredients];
}

@end
</code></pre>

<p>And the code for creating the curry recipe becomes this, for which Xcode will give helpful Code Sense completion suggestions:</p>

<pre><code>NSMutableSet *ingredients = panangCurryRecipe.mutableIngredients;

[ingredients addObject:[Ingredient ingredientWithName:@"Butternut Squash" quantity:1]];
[ingredients addObject:[Ingredient ingredientWithName:@"Panang Curry Paste" quantity:1]];
[ingredients addObject:[Ingredient ingredientWithName:@"Coconut Milk" quantity:1]];
</code></pre>

<p>As well, it continues to avoid making copies of the underlying collection representing the relationship, and it also continues to post fine-grained KVO change notifications rather than whole-property notifications, ensuring bound controls are updated efficiently.</p>

<p>So when you&#8217;re creating properties for to-many relationships whether they&#8217;re unordered (NSSet) or ordered (NSArray), consider using this approach to implementing them.  It&#8217;ll take a little more code, but it&#8217;ll be a lot more efficient and more correct.</p>

<h4>Bonus Round: Core Data</h4>

<p>What about Core Data?  Now that iPhone OS 3.0 has Core Data, in addition to Mac OS X, there&#8217;s <strong>really</strong> no excuse not to use it.  But would you do anything differently above?</p>

<p>Of course.  But since we&#8217;re talking about Core Data, it turns out that what you do different is actually <em>write a whole lot less code</em>.  Here&#8217;s what the declaration of the Recipe class will look like if it corresponds to a Core Data entity:</p>

<pre><code>@interface Recipe : NSManagedObject

@property (copy) NSSet *ingredients;
@property (readonly, copy) NSMutableSet *mutableIngredients;

@end

@interface Recipe (CoreDataGeneratedAccessors)

- (void)addIngredientsObject:(Ingredient *)ingredient;
- (void)removeIngredientsObject:(Ingredient *)ingredient;

- (void)addIngredients:(NSSet *)ingredients;
- (void)removeIngredients:(NSet *)ingredients;

@end
</code></pre>

<p>Notice that I&#8217;ve gotten rid of the instance variables section entirely.  This is because Core Data manages the storage for your modeled attributes and relationships for you; you don&#8217;t need (and <em>really</em> don&#8217;t want) instance variables for them.</p>

<p>You&#8217;ll also notice that I put the additional to-many relationship accessor methods in their own category.  To see why, take a look at the implementation of the class:</p>

<pre><code>@implementation Recipe

@dynamic ingredients;

- (NSMutableSet *)mutableIngredients {
    return [self mutableSetValueForKey:@"ingredients"];
}

@end
</code></pre>

<p>Notice anything missing?  <em>All of the methods related to the modeled <code>ingredients</code> property!</em>  Core Data will not only generate an efficient setter and getter for the <code>ingredients</code> property automatically at run time, but will <em>also</em> generate implementations for the other <code>ingredients</code> to-many relationship accessor methods as well!</p>

<p>Core Data will generate the methods (at the latest) when you try to use them; it&#8217;s not dependent on having the category declaration available.  That&#8217;s just for the compiler and IDE&#8217;s benefit when you&#8217;re writing code that <em>uses</em> those methods, so they can be completed by Code Sense and the compiler knows not to generate unknown-method warnings.</p>

<h4>Changes</h4>

<p>I added a bit after the first use of <code>-mutableSetValueForKey:</code> to address why one might want to use the mutable set proxy rather than just using the finer-grained KVC accessor methods directly.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=189</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Singletons in Cocoa/Objective-C</title>
		<link>http://eschatologist.net/blog/?p=178</link>
		<comments>http://eschatologist.net/blog/?p=178#comments</comments>
		<pubDate>Wed, 17 Jun 2009 03:51:35 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[design patterns]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[unit testing]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=178</guid>
		<description><![CDATA[I&#8217;ll preface this post with the standard advice: Don&#8217;t create singletons if you don&#8217;t absolutely have to. In general, if you&#8217;re creating a global &#8220;manager&#8221; object of some sort, you&#8217;re doing something wrong. That said, there&#8217;s still occasionally a reason to have such a global singleton, such as a &#8220;default something.&#8221; The sample code in [...]]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ll preface this post with the standard advice:  <em>Don&#8217;t create singletons if you don&#8217;t absolutely have to.</em>  In general, if you&#8217;re creating a global &#8220;manager&#8221; object of some sort, you&#8217;re doing something wrong.</p>

<p>That said, there&#8217;s still occasionally a reason to have such a global singleton, such as a &#8220;default something.&#8221;  The sample code in the <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32">Cocoa Fundamentals Guide</a> goes to a lot more trouble than it needs to in order to <em>ensure</em> that a class is a singleton.</p>

<p>This is almost <strong>never</strong> what you want.</p>

<p>First off, you probably want your class to be testable in a variety of configurations.  In your unit tests, instead of getting your shared singleton instance in your <code>-setUp</code> method and &#8220;resetting&#8221; its state in <code>-tearDown</code>, you&#8217;d be better off just instantiating a <em>new</em> instance in <code>-setUp</code> and <em>releasing</em> it in <code>-tearDown</code>.</p>

<p>Also, the example in the Cocoa Fundamentals Guide does a lot of work that it simply doesn&#8217;t need to.  This is all you <em>really</em> need to do to create a singleton in Cocoa:</p>

<pre><code>@interface SomeManager : NSObject
+ (id)sharedManager;
@end

@implementation SomeManager

+ (id)sharedManager {
    static id sharedManager = nil;

    if (sharedManager == nil) {
        sharedManager = [[self alloc] init];
    }

    return sharedManager;
}

@end
</code></pre>

<p>That&#8217;s it!  The astute reader will notice, of course, that this isn&#8217;t thread-safe.  I got rid of the <code>@synchronized (self)</code> because it won&#8217;t do the right thing; depending on what actual class is sent <code>+sharedManager</code>, the value of <code>self</code> will be different!</p>

<p>For the sake of argument, though, let&#8217;s say that you do want a singleton with which you can interact from multiple threads at once.  One way to do this would be to create your singleton instance in <code>+initialize</code> since it will always be run, on a single thread, before any other methods in your class:</p>

<pre><code>@implementation SomeManager

static id sharedManager = nil;

+ (void)initialize {
    if (self == [SomeManager class]) {
        sharedManager = [[self alloc] init];
    }
}

+ (id)sharedManager {
    return sharedManager;
}

@end
</code></pre>

<p>By doing this, you avoid the performance bottleneck of <code>@synchronized</code> taking a recursive lock every time <code>+sharedManager</code> is invoked.</p>

<p>If you want to get fancier, and it&#8217;s OK to temporarily have more than one instance of your singleton created, you could even use <code>objc_atomicCompareAndSwapGlobalBarrier</code> to assign the value to return from <code>+sharedManager</code>, though this is probably also more work than it&#8217;s worth; after all, <code>+initialize</code> will only be invoked once for your class.  (Though it can be re-invoked as a side-effect of initializing subclasses, hence the <code>if (self == [SomeManager class]) { }</code> idiom.)</p>

<p>In all of the above cases, you&#8217;ve done a whole lot less work than the example in the Cocoa Fundamentals Guide, and your code is a lot more likely to be correct as a result.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=178</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>When to use properties &amp; dot notation</title>
		<link>http://eschatologist.net/blog/?p=160</link>
		<comments>http://eschatologist.net/blog/?p=160#comments</comments>
		<pubDate>Thu, 28 May 2009 03:14:27 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[OOP]]></category>
		<category><![CDATA[podcasts]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=160</guid>
		<description><![CDATA[I listened to a recent episode of the cocoaFusion: podcast about properties and dot notation today. There were a few interesting points brought up, but I felt a couple of the most important reasons to use @property declarations and dot notation weren&#8217;t addressed. The biggest reason I see to use a different notation for both [...]]]></description>
				<content:encoded><![CDATA[<p>I listened to a recent episode of the <a href="http://www.cocoafusion.net/" title="cocoaFusion: podcast">cocoaFusion:</a> podcast about properties and dot notation today.  There were a few interesting points brought up, but I felt a couple of the most important reasons to use <code>@property</code> declarations and dot notation weren&#8217;t addressed.</p>

<p>The biggest reason I see to use a different notation for both property declaration and property access than for method declaration and sending messages — even if property access ultimately results in a message send, as it does in Objective-C 2.0 — is <strong>separation of state and behavior</strong>.</p>

<p>In the ur-OOP days of Smalltalk, state was supposed to be <em>encapsulated</em> within objects <em>entirely</em>.  This has become Smalltalk dogma and some developers have tried to propagate it to Objective-C:  The idea that objects should <em>never</em> expose their state to each other, but instead only vend <em>behaviors</em>.  It makes a certain amount of sense if you see objects purely as actors.</p>

<p>However, in today&#8217;s modern world we understand that objects aren&#8217;t <em>just</em> actors.  Objects both &#8220;do things&#8221; <em>and</em> &#8220;represent things;&#8221; they&#8217;re nouns.  And they have both <em>internal</em> state that they use in managing their behavior and <em>external</em> state they expose to the world.</p>

<p>You can use the same mechanism to do both, as Smalltalk does and as Objective-C did before 2007.  However, it turns out that it can make a lot more sense to use different syntax to represent the distinct concepts, even if they&#8217;re handled by the same underlying mechanism.</p>

<p>For example, I might have a Person class and an NSViewController subclass that presents a Person instance in a view.  The API to my Person class might look like this:</p>

<pre><code>@interface Person : NSObject
@property (copy) NSString *name;
@property (copy) NSImage *picture;
@end
</code></pre>

<p>This sends a strong signal to the users of the class that <code>name</code> and <code>picture</code> are <em>external</em> state for a Person instance, leading me to write code like this:</p>

<pre><code>Person *person = [[Person alloc] init];
person.name = @"Chris";
person.picture = pictureOfChris;
</code></pre>

<p>The intent of this code is clear: I&#8217;m not asking <code>person</code> to do anything, I&#8217;m just manipulating its external state.  That may cause it to do things as a side-effect, but at least in the code snippet I&#8217;m looking at, I&#8217;m just interested in changing some state.</p>

<p>Now let&#8217;s see what the NSViewController might look like:</p>

<pre><code>@interface PersonViewController : NSViewController
@property (retain) Person *person;
- (BOOL)updatePicture;
@end
</code></pre>

<p>And let&#8217;s see how I&#8217;d use one, assuming it&#8217;s been instantiated and wired up in my view hierarchy already:</p>

<pre><code>selectedPersonViewController.person = person;

if ([selectedPersonViewController updatePicture]) {
    // note elsewhere that the person's picture is updated
}
</code></pre>

<p>Even though the <code>-updatePicture</code> method has no arguments and returns a <code>BOOL</code> I (1) don&#8217;t make it a property and (2) don&#8217;t use dot notation to invoke it.  Why not, since it fits the <em>form</em> of a property?  Because it doesn&#8217;t fit the <em>intent</em> of a property.  I&#8217;m actually telling the view controller to perform some action, not just changing some state, and I want the intent of that to be clear to a reader of the above code.</p>

<p>That brings me to the other major reason to both declare properties using <code>@property</code> and use dot notation to access them:  Xcode.  The code completion technology in Xcode tries hard to provide you with a good default completion and good choices in the completion list.  But this can be very difficult, especially with the combination of Objective-C&#8217;s dynamic dispatch and the sheer size of the frameworks:  There are hundreds (!) of methods declared in categories on NSObject as a result of categories describing informal protocols, and any of those methods could be valid on an arbitrary instance.</p>

<p>Dot notation, on the other hand, is <strong>not</strong> valid on arbitrary objects.  Even though it compiles to exactly the same sort of <code>objc_msgSend</code> dynamic dispatch that bracket notation does, from a type system perspective it actually <strong>requires</strong> a declaration of the property being accessed to work correctly.  The reason for this is that the name of a property is not necessarily the name of the message selector to use in dispatch; think of a property <code>hidden</code> whose underlying getter method is named <code>-isHidden</code>.</p>

<p>This means that tools like Xcode can provide a much more streamlined experience for properties using dot notation.  If I write the above code in Xcode, rather than MarsEdit, Xcode will not offer completions like <code>-autorelease</code> and <code>-retainCount</code> when I type <code>person.</code> — it will only offer me the properties it knows are on Person.</p>

<p>Now, you <em>can</em> invoke arbitrary getters or setters (so long as they have a corresponding getter) using dot notation.  The compiler doesn&#8217;t require an <code>@property</code> declaration for the use of dot notation, just a declaration.  I could have declared the <code>Person.name</code> property like this:</p>

<pre><code>@interface Person : NSObject
- (NSString *)name;
- (void)setName:(NSString *)value;
@end
</code></pre>

<p>The compiler will compile <code>person.name = @"Chris";</code> just fine with this declaration, to an invocation of <code>-[Person setName:]</code> — but Xcode won&#8217;t offer you code completion for it if you don&#8217;t use <code>@property</code> to declare it.  By not offering to complete non-<code>@property</code> properties for dot notation, Xcode avoids offering you <em>bad</em> completions like <code>autorelease</code> and <code>retain</code> that are technically allowed but are abominable style.</p>

<p>Of course, one complication is that many frameworks on Mac OS X predate <code>@property</code> declarations and thus don&#8217;t expose their state this way.  That means Xcode won&#8217;t offer you completions for their state with dot notation until those frameworks do.  Fortunately for iPhone developers, UIKit uses <code>@property</code> declarations pervasively.  You should too.</p>

<p>To sum up:</p>

<ul>
<li>Use <code>@property</code> to declare the state exposed by your objects.</li>
<li>Use dot notation to get and set objects&#8217; state.</li>
<li>Use method declarations to declare the behavior exposed by your objects.</li>
<li>Use bracket notation to invoke objects&#8217; behavior.</li>
</ul>

<p>This results in intention-revealing code that clearly separates state and behavior both in declaration and use.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=160</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Five years!</title>
		<link>http://eschatologist.net/blog/?p=168</link>
		<comments>http://eschatologist.net/blog/?p=168#comments</comments>
		<pubDate>Mon, 13 Apr 2009 03:08:31 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Core Data]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=168</guid>
		<description><![CDATA[As of today, I&#8217;ve been with Apple for five years, working on developer tools. It&#8217;s been great and I look forward to many more years of improving the experience for people creating great Mac and iPhone software!]]></description>
				<content:encoded><![CDATA[<p>As of today, I&#8217;ve been with Apple for five years, working on developer tools.</p>

<p>It&#8217;s been great and I look forward to many more years of improving the experience for people creating great Mac and iPhone software!</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=168</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Go ahead and use Core Data</title>
		<link>http://eschatologist.net/blog/?p=164</link>
		<comments>http://eschatologist.net/blog/?p=164#comments</comments>
		<pubDate>Wed, 25 Mar 2009 01:05:55 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Core Data]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[SQLite]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=164</guid>
		<description><![CDATA[In a few weeks, it will be four years since Mac OS X 10.4 Tiger was first released. That was the first release to include Core Data. It will also be about one and a half years since Mac OS X 10.5 Leopard was released, with significant enhancements to the Core Data API. It&#8217;s pretty [...]]]></description>
				<content:encoded><![CDATA[<p>In a few weeks, it will be <strong>four years</strong> since Mac OS X 10.4 Tiger was first released. That was the first release to include Core Data. It will also be about <strong>one and a half years</strong> since Mac OS X 10.5 Leopard was released, with significant enhancements to the Core Data API.</p>

<p>It&#8217;s pretty safe to start using Core Data in your applications now. You certainly don&#8217;t need to wrote directly to the low-level SQLite API any more.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=164</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>No NSCoder Night for me tonight</title>
		<link>http://eschatologist.net/blog/?p=95</link>
		<comments>http://eschatologist.net/blog/?p=95#comments</comments>
		<pubDate>Wed, 04 Feb 2009 02:48:05 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[NSCoder Night]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=95</guid>
		<description><![CDATA[Unfortunately I&#8217;m not feeling well, so I won&#8217;t be at NSCoder Night tonight. See everyone next week!]]></description>
				<content:encoded><![CDATA[<p>Unfortunately I&#8217;m not feeling well, so I won&#8217;t be at NSCoder Night tonight. See everyone next week!</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=95</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Happy 25, Macintosh!</title>
		<link>http://eschatologist.net/blog/?p=5</link>
		<comments>http://eschatologist.net/blog/?p=5#comments</comments>
		<pubDate>Sat, 24 Jan 2009 20:29:22 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Mac]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=5</guid>
		<description><![CDATA[The Mac is 25 years old today. Happy birthday, Macintosh. You&#8217;ve really changed the world.]]></description>
				<content:encoded><![CDATA[<p>The Mac is 25 years old today.</p>

<p>Happy birthday, Macintosh.  You&#8217;ve really changed the world.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=5</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DDJ vs. Backyard Poultry</title>
		<link>http://eschatologist.net/blog/?p=102</link>
		<comments>http://eschatologist.net/blog/?p=102#comments</comments>
		<pubDate>Thu, 09 Oct 2008 06:25:00 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[magazines]]></category>
		<category><![CDATA[publishing]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=102</guid>
		<description><![CDATA[Eric Sink has a post talking about the sad state of developer publishing, specifically discussing the declining readership of the venerable developer magazine Dr. Dobb&#8217;s Journal, as compared to that mainstay of American newsstands Backyard Poultry. After reading the article and the replies, I just had to throw in my two cents about magazine publishing [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.ericsink.com/">Eric Sink</a> has a post talking about the <a href="http://www.ericsink.com/entries/poultry_magazines.html">sad state of developer publishing</a>, specifically discussing the declining readership of the venerable developer magazine <cite><a href="http://www.ddj.com/">Dr. Dobb&#8217;s Journal</a></cite>, as compared to that mainstay of American newsstands <cite><a href="http://www.backyardpoultrymag.com/">Backyard Poultry</a></cite>.</p>

<p>After reading the article and the replies, I just had to throw in my two cents about magazine publishing and why &#8220;1% of the US population are software developers, so there should be a huge market for development magazines.&#8221;</p>

<p>It&#8217;s a significant mistake to think that <strong>the reader</strong> is the target and that <strong>the magazine</strong> is the product.</p>

<p>It is actually <strong>the aggregate readership</strong> that is the product, and <strong>the advertisers</strong> who are the target.  That is, unless the magazine takes no advertising and is entirely supported by its subscribers.</p>

<p>This was driven home to me recently when I bought the recent &#8220;eInk Flashing Cover&#8221; issue of <cite>Esquire</cite>.  I had never read <cite>Esquire</cite> before, so in addition to checking out the cool hardware on the cover, I started trying to read it.  It was way more full of ads than <cite>Wired</cite> ever was — even in the days when <a href="http://www.suck.com/daily/95/10/06/daily.html">Suck famously disassembled <cite>Wired</cite> 3.09 to remove the ads</a>.</p>

<p>Furthermore, its advertisers were all very high-end.  Thus I wasn&#8217;t that surprised when I saw that the price on the subscription card for a year of <cite>Esquire</cite> was well under $1/issue.</p>

<p>So if <cite>Dr. Dobb&#8217;s Journal</cite> is circling the drain, it&#8217;s not the current readership that&#8217;s to be blamed, or the Internet.  It&#8217;s the lack of advertisers interested in reaching that readership, or the magazine&#8217;s ability to reach a readership that is interesting to a better-paying tier of advertisers.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=102</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Let&#8217;s merge managed object models!</title>
		<link>http://eschatologist.net/blog/?p=85</link>
		<comments>http://eschatologist.net/blog/?p=85#comments</comments>
		<pubDate>Sat, 27 Sep 2008 23:53:00 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Core Data]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=85</guid>
		<description><![CDATA[There was a question recently on Stack Overflow asking how to handle cross-model relationships in managed object models. Now, the poster wasn&#8217;t asking about how to handle relationships across persistent stores — he was asking how to handle splitting a model up into pieces such that the pieces could be recombined. It turns out that [...]]]></description>
				<content:encoded><![CDATA[<p>There was a question recently on <a href="http://stackoverflow.com/">Stack Overflow</a> asking <a href="http://stackoverflow.com/questions/130316/cross-model-relationships-in-nsmanagedobjectmodel-from-merged-models">how to handle cross-model relationships in managed object models</a>.  Now, the poster wasn&#8217;t asking about how to handle relationships across <em>persistent stores</em> — he was asking how to handle splitting a model up into pieces such that the pieces could be recombined.</p>

<p>It turns out that this is somewhat straightforward to do using Core Data.  Let&#8217;s say you have a simple model with Song and Artist entities.  I&#8217;ll write it out here in a pseudo-modeling language for ease of reading:  <code></p>

<pre>MusicModel = {
    Song = {
        attribute title : string;
        attribute duration : float;
        to-one-relationship artist : Artist,
            inverse : songs,
            delete-rule : nullify;
        userInfo = { };
    };

    Artist = {
        attribute name : string;
        to-many-relationship songs : Song,
            inverse : artist,
            delete-rule : cascade;
        userInfo = { };
    };
};</pre>

<p></code>  Now let&#8217;s say you want to split this up into two models, where Song is in one and Artist is in the other.  You could just try and create two <code>xcdatamodel</code> files in Xcode, one with each entity, and wire the relationships together after loading them and merging them with <code><a href="http://developer.apple.com/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectModel_Class/Reference/Reference.html#//apple_ref/occ/clm/NSManagedObjectModel/modelByMergingModels:">+[NSManagedObjectModel modelByMergingModels:]</a></code>.  Except that won&#8217;t work:  Relationships with no destination entity won&#8217;t be compiled by the model compiler.</p>

<p>What else might you try?  You could try just putting dummy entities in for relationships to point to.  However, merging models will fail then, because <a href="http://developer.apple.com/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectModel_Class/Reference/Reference.html">NSManagedObjetModel</a> won&#8217;t merge models that have entity name collisions.</p>

<p>It turns out, though, that you can merge models very easily by hand, by taking advantage of the way Core Data&#8217;s model-description objects handle the <code>NSCopying</code> protocol.  All you have to do is create your destination model, loop through every entity in each of your source  models, and copy every entity that you <em>haven&#8217;t</em> tagged as a stand-in using a special key in their <code>userInfo</code> dictionary.</p>

<p>Why does this work?  The trick is that before you tell a persistent store coordinator to <em>use</em> a model, that model is mutable and references relationship destination entities and inverse relationships by <em>name</em>.  So you can have only a minimal representation of Artist in one model, and a minimal representation of Song in another model:  <code></p>

<pre>SongModel = {
    Song = {
        attribute title : string;
        attribute duration : float;
        to-one-relationship artist : Artist,
            inverse : songs,
            delete-rule : nullify;
        userInfo = { };
    };

    Artist = {
        /* Note no attributes. */
        to-many-relationship songs : Song,
            inverse : artist,
            delete-rule : cascade;
        userInfo = { IsPlaceholder = YES; };
    };
};

ArtistModel = {
    Song = {
        /* Note no attributes. */
        to-one-relationship artist : Artist,
            inverse : songs,
            delete-rule : nullify;
        userInfo = { IsPlaceholder = YES; };
    };

    Artist = {
        attribute name : string;
        to-many-relationship songs : Song,
            inverse : artist,
            delete-rule : cascade;
        userInfo = { };
    };
};</pre>

<p></code>  Then, when you write some code to combine them, the merged model will wind up with the full definition of Song and the full definition of Artist.  Here&#8217;s an example of the code you might write to do this:  <code></p>

<pre>- (NSManagedObjectModel *)mergeModelsReplacingDuplicates:(NSArray *)models {
    NSManagedObjectModel *mergedModel = [[[NSManagedObjectModel alloc] init] autorelease];

    // General strategy:  For each model, copy its non-placeholder entities
    // and add them to the merged model. Placeholder entities are identified
    // by a MyRealEntity key in their userInfo (which names their real entity,
    // though their mere existence is sufficient for the merging).

    NSMutableArray *mergedModelEntities = [NSMutableArray arrayWithCapacity:0];

    for (NSManagedObjectModel *model in models) {
        for (NSEntityDescription *entity in [model entities]) {
            if ([[[entity userInfo] objectForKey:@"IsPlaceholder"] boolValue]) {
                // Ignore placeholder.
            } else {
                NSEntityDescription *newEntity = [entity copy];
                [mergedModelEntities addObject:newEntity];
                [newEntity release];
            }
        }
    }

    [mergedModel setEntities:mergedModelEntities];

    return mergedModel;
}</pre>

<p></code>  This may seem like a bit of overhead for this simple example.  The critical thing to see above is that <em>only that which is necessary for model consistency is in the placeholder entities</em>.  Thus you only need the inverse relationship from Song to Artist in ArtistModel.  Say you wanted to add a Picture entity related to the Artist entity — you don&#8217;t have to add that to both models, only to ArtistModel.  The benefit of this method for merging models should then be pretty apparent:  It gives you the ability to make your model separable, just like your code.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=85</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erlang on LLVM? or: Outsource your JIT!</title>
		<link>http://eschatologist.net/blog/?p=46</link>
		<comments>http://eschatologist.net/blog/?p=46#comments</comments>
		<pubDate>Mon, 25 Aug 2008 02:36:00 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[compilers]]></category>
		<category><![CDATA[CouchDB]]></category>
		<category><![CDATA[ejabberd]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Jabber]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[LLVM]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[XMPP]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=46</guid>
		<description><![CDATA[Has anyone been working on using LLVM to do just-in-time code generation for the Erlang virtual machine? Depending on the design and structure of the Erlang virtual machine, it doesn&#8217;t seem like it would be all that tough a project. And it could provide a nice performance boost for those projects that are starting to [...]]]></description>
				<content:encoded><![CDATA[<p>Has anyone been working on using <a href="http://llvm.org/">LLVM</a> to do just-in-time code generation for the <a href="http://erlang.org/">Erlang</a> virtual machine?</p>

<p>Depending on the design and structure of the Erlang virtual machine, it doesn&#8217;t seem like it would be all that tough a project.  And it could provide a nice performance boost for those projects that are starting to use Erlang like <a href="http://couchdb.org/">CouchDB</a> and <a href="http://www.ejabberd.im/">ejabberd</a>.</p>

<p>For an example of what I&#8217;m talking about, there&#8217;s a project called <a href="http://www.ejabberd.im/">VMKit</a> that has implemented the Java and .NET virtual machines atop LLVM with reasonable performance.  Essentially, if you have a virtual machine, rather than skipping either just-in-time or static code generation entirely, or trying to do it all yourself for some specific platform on which you want to run, take a look at what you can do with LLVM and see if you can leverage its code generation instead.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=46</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Not it!</title>
		<link>http://eschatologist.net/blog/?p=104</link>
		<comments>http://eschatologist.net/blog/?p=104#comments</comments>
		<pubDate>Tue, 29 Jul 2008 09:21:00 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=104</guid>
		<description><![CDATA[I didn&#8217;t write Carrie&#8217;s Dots — but I did download it! It was written by Dr. Chris Hanson, a Chris Hanson who&#8217;s evidently still in the mid-South. Maybe the next time I get a chance to visit Mississippi, we&#8217;ll get to meet up!]]></description>
				<content:encoded><![CDATA[<p>I didn&#8217;t write <em><a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=286047207&amp;mt=8">Carrie&#8217;s Dots</a></em> — but I did download it!</p>

<p>It was written by <a href="http://dr-chris.org/"><strong>Dr.</strong> Chris Hanson</a>, a Chris Hanson who&#8217;s evidently still in the mid-South.  Maybe the next time I get a chance to visit Mississippi, we&#8217;ll get to meet up!</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=104</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>LLVM terminology</title>
		<link>http://eschatologist.net/blog/?p=48</link>
		<comments>http://eschatologist.net/blog/?p=48#comments</comments>
		<pubDate>Fri, 18 Jul 2008 16:52:00 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[compilers]]></category>
		<category><![CDATA[LLVM]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=48</guid>
		<description><![CDATA[I thought the proper terminology was worth pointing out, since I&#8217;ve seen — and heard — some misuses lately. LLVM is the Low-Level Virtual Machine and the project surrounding it. LLVM-GCC is a compiler that uses GCC for its front-end and LLVM for its back-end. Clang is the C language family front-end that is part [...]]]></description>
				<content:encoded><![CDATA[<p>I thought the proper terminology was worth pointing out, since I&#8217;ve seen — and heard — some misuses lately.</p>

<ul>
<li><p><strong><a href="http://llvm.org/">LLVM</a></strong> is the Low-Level Virtual Machine and the project surrounding it.</p></li>
<li><p><strong><a href="http://llvm.org/docs/CommandGuide/html/llvmgcc.html">LLVM-GCC</a></strong> is a compiler that uses GCC for its front-end and LLVM for its back-end.</p></li>
<li><p><strong><a href="http://clang.llvm.org/">Clang</a></strong> is the C language family front-end that is part of the LLVM project.  It&#8217;s a parser, semantic analyzer, and code generator — in other words, a compiler front-end that uses LLVM for its back-end.</p></li>
<li><p><strong><a href="http://clang.llvm.org/StaticAnalysis.html">The Clang Static Analyzer</a></strong> is what people have been trying out lately, to find subtle bugs in their and other projects.  It&#8217;s a great tool.</p></li>
</ul>

<p>I just thought this was important to mention, because people have been referring to &#8220;LLVM&#8221; instead of &#8220;LLVM-GCC&#8221; in reference to the compiler included in Xcode 3.1, and people have been referring to &#8220;Clang&#8221; instead of &#8220;the Clang Static Analyzer&#8221; in reference to what they&#8217;ve been using to find bugs in their projects.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=48</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New bike! Marin Belvedere 2007</title>
		<link>http://eschatologist.net/blog/?p=106</link>
		<comments>http://eschatologist.net/blog/?p=106#comments</comments>
		<pubDate>Sun, 06 Jul 2008 04:52:00 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[bicycle]]></category>
		<category><![CDATA[climate crisis]]></category>
		<category><![CDATA[conservation]]></category>
		<category><![CDATA[ecology]]></category>
		<category><![CDATA[transportation]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=106</guid>
		<description><![CDATA[I just got my first bike since junior high, and rode a bike today for the first time since high school! Many thanks to Meg for helping me pick it out and to Dan and others for listening to me ramble about what I might or might not want. What I wound up getting was [...]]]></description>
				<content:encoded><![CDATA[<p>I just got my first bike since junior high, and rode a bike today for the first time since high school!  Many thanks to <a href="http://jighexadecimal.com/">Meg</a> for helping me pick it out and to <a href="http://razorwind.org/">Dan</a> and others for listening to me ramble about what I might or might not want.</p>

<p>What I wound up getting was a <a href="http://www.marinbikes.com/bicycles_2007/html/bikes/bike_specs/specs_belvedere.html">2007 Belvedere</a> from <a href="http://www.marinbikes.com/">Marin Bikes</a>, in matte coal (of course).  I test-rode it and it felt great, I could even shift — something I could never do in junior high or high school without losing control, damn post-shifters — and the only limit I felt with it was me!</p>

<p>So after accessorizing a bit, Meg and I rode home and then walked back to pick up the car.  Cupertino and the South Bay in general are so bike-friendly I can tell I&#8217;m going to put a <em>lot</em> of miles on it just this summer, and if I get a good set of panniers there&#8217;s no reason I won&#8217;t be able to keep doing so into the fall and even winter.</p>

<p>And as tired as I am just from riding a couple miles today, it feels a hell of a lot better than contributing to the climate crisis while paying nearly $5/gallon for gasoline.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=106</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Always use notification name globals, not string literals!</title>
		<link>http://eschatologist.net/blog/?p=108</link>
		<comments>http://eschatologist.net/blog/?p=108#comments</comments>
		<pubDate>Sat, 28 Jun 2008 22:58:00 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=108</guid>
		<description><![CDATA[What&#8217;s wrong with this code? - (void)registerForNotificationsFromTask:(NSTask *)task ( { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidTerminateNotification:) name:@"NSTaskDidTerminateNotification" object:task]; } If you didn&#8217;t notice anything wrong, look again. What&#8217;s bad about this is that it&#8217;s passing a string literal instead of a global variable for the notification name. The code should really look like this: - (void)registerForNotificationsFromTask:(NSTask *)task [...]]]></description>
				<content:encoded><![CDATA[<p>What&#8217;s wrong with this code?</p>

<pre><code>- (void)registerForNotificationsFromTask:(NSTask *)task ( {
    [[NSNotificationCenter defaultCenter]
        addObserver:self
           selector:@selector(taskDidTerminateNotification:)
               name:@"NSTaskDidTerminateNotification"
             object:task];
}
</code></pre>

<p>If you didn&#8217;t notice anything wrong, look again.</p>

<p>What&#8217;s bad about this is that it&#8217;s passing a <strong>string literal</strong> instead of a <strong>global variable</strong> for the notification name.  The code should really look like this:</p>

<pre><code>- (void)registerForNotificationsFromTask:(NSTask *)task ( {
    [[NSNotificationCenter defaultCenter]
        addObserver:self
           selector:@selector(taskDidTerminateNotification:)
               name:NSTaskDidTerminateNotification
             object:task];
}
</code></pre>

<p>Isn&#8217;t that better?  (Among other things, Xcode will offer to complete the <code>NSTaskDidTerminateNotification</code> global variable for you — unlike the contents of a string literal.)</p>

<p>This is a bug that often results from copying &amp; pasting from documentation into code.  &#8220;I need this notification, it needs to be a string, so I&#8217;ll just put <code>@""</code> around it.&#8221;  The <em>type</em> of a notification name is, in fact, <code>NSString</code> but you don&#8217;t have to pass a <em>string literal</em> for that.  Instead, pass the global variable that exists for each notification name and you&#8217;re guaranteed that the right thing will happen.</p>

<p>If you&#8217;re creating and using your own notifications, be sure to follow the Cocoa pattern and create your own global variables containing the notification name.  Otherwise you&#8217;re at the mercy of typos within string literals.</p>

<p><strong>Update:</strong> Sanjay Samani helpfully pointed out that by <em>constant string</em> I meant <em>string literal</em>.  Thanks, Sanjay!  I&#8217;ve updated my post with this correction.  (Not sure where my memory was…)</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=108</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I fucking hate this city</title>
		<link>http://eschatologist.net/blog/?p=112</link>
		<comments>http://eschatologist.net/blog/?p=112#comments</comments>
		<pubDate>Wed, 11 Jun 2008 04:22:00 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[bicycle]]></category>
		<category><![CDATA[hate]]></category>
		<category><![CDATA[San Francisco]]></category>
		<category><![CDATA[theft]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=112</guid>
		<description><![CDATA[Meg rode her bike down from the hotel to Union Square to meet me for dinner, locking it up at a bike station right outside Borders. After we walked back from dinner, we discovered it had been stolen. Right in the middle of dinner, right on the corner of fucking Union Square. I fucking hate [...]]]></description>
				<content:encoded><![CDATA[<p>Meg rode her bike down from the hotel to Union Square to meet me for dinner, locking it up at a bike station right outside Borders.</p>

<p>After we walked back from dinner, we discovered it had been stolen.  Right in the middle of dinner, right on the corner of fucking Union Square.</p>

<p>I fucking hate San Francisco.  What a shit-hole of a city.</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=112</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WWDC 2008</title>
		<link>http://eschatologist.net/blog/?p=114</link>
		<comments>http://eschatologist.net/blog/?p=114#comments</comments>
		<pubDate>Mon, 09 Jun 2008 07:56:00 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[conferences]]></category>
		<category><![CDATA[conventions]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[WWDC]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=114</guid>
		<description><![CDATA[The time is upon us once again — WWDC time! As I have the past few years, I&#8217;ll be in San Francisco all week, staying at the Hotel Kabuki in Japantown. And of course, I&#8217;ll be around the conference all week — especially in the labs. Come by and say hi, and I&#8217;ll be happy [...]]]></description>
				<content:encoded><![CDATA[<p>The time is upon us once again — <a href="http://developer.apple.com/wwdc/">WWDC</a> time!</p>

<p>As I have the past few years, I&#8217;ll be in San Francisco all week, staying at the <a href="http://www.jdvhotels.com/kabuki/">Hotel Kabuki</a> in <a href="http://www.sfjapantown.org/">Japantown</a>.</p>

<p>And of course, I&#8217;ll be around the conference all week — especially in the labs.  Come by and say hi, and I&#8217;ll be happy to help with any questions you have!</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=114</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>No NSCoder night for me tonight!</title>
		<link>http://eschatologist.net/blog/?p=116</link>
		<comments>http://eschatologist.net/blog/?p=116#comments</comments>
		<pubDate>Wed, 04 Jun 2008 01:23:00 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[CocoaHeads]]></category>
		<category><![CDATA[conferences]]></category>
		<category><![CDATA[get-togethers]]></category>
		<category><![CDATA[IRC]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[NSCoder Night]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[WWDC]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=116</guid>
		<description><![CDATA[I&#8217;d like to make it to NSCoder Night tonight, but I just have too much else to do today — again. I won&#8217;t be seeing anyone at NSCoder Night next week, either, as I&#8217;ll be in San Francisco for the Apple Worldwide Developers Conference! If you&#8217;re attending, be sure to find me and say hi!]]></description>
				<content:encoded><![CDATA[<p>I&#8217;d like to make it to <a href="http://nscodernight.com/">NSCoder Night</a> tonight, but I just have too much else to do today — again.</p>

<p>I won&#8217;t be seeing anyone at NSCoder Night next week, either, as I&#8217;ll be in San Francisco for the <a href="http://developer.apple.com/wwdc/">Apple Worldwide Developers Conference</a>!  If you&#8217;re attending, be sure to find me and say hi!</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=116</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>No NSCoder night for me tonight!</title>
		<link>http://eschatologist.net/blog/?p=120</link>
		<comments>http://eschatologist.net/blog/?p=120#comments</comments>
		<pubDate>Wed, 28 May 2008 00:15:00 +0000</pubDate>
		<dc:creator>eschaton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[CocoaHeads]]></category>
		<category><![CDATA[get-togethers]]></category>
		<category><![CDATA[IRC]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[NSCoder Night]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://eschatologist.net/blog/?p=120</guid>
		<description><![CDATA[I&#8217;d like to make it to NSCoder Night tonight, but I just have too much else to do today. Hopefully I&#8217;ll see everyone there next week!]]></description>
				<content:encoded><![CDATA[<p>I&#8217;d like to make it to <a href="http://nscodernight.com/">NSCoder Night</a> tonight, but I just have too much else to do today.  Hopefully I&#8217;ll see everyone there next week!</p>
]]></content:encoded>
			<wfw:commentRss>http://eschatologist.net/blog/?feed=rss2&#038;p=120</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.929 seconds -->
