<?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>manicwave.com &#187; cocoa</title>
	<atom:link href="http://www.manicwave.com/blog/category/blog/cocoa/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.manicwave.com/blog</link>
	<description>surf the wave</description>
	<lastBuildDate>Thu, 04 Mar 2010 16:48:24 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Sharpening the code coverage saw</title>
		<link>http://www.manicwave.com/blog/2010/03/04/sharpening-the-code-coverage-saw/</link>
		<comments>http://www.manicwave.com/blog/2010/03/04/sharpening-the-code-coverage-saw/#comments</comments>
		<pubDate>Thu, 04 Mar 2010 16:48:23 +0000</pubDate>
		<dc:creator>jschi</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Unit Testing]]></category>
		<category><![CDATA[cocoa]]></category>
		<category><![CDATA[xcode]]></category>

		<guid isPermaLink="false">http://www.manicwave.com/blog/?p=1781</guid>
		<description><![CDATA[Here&#8217;s a quick followup to my Hudson &#8211; Cocoa &#8211; Coverage Reporting blog post from the other day.
I didn&#8217;t show the summary output that Cobertura displays in Hudson. &#160;It looked like this:

You&#8217;ll note (or I will do so for you) that there&#8217;s a variety of packages here (in the cocoa case, these are just subdirectories [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a quick followup to my <a href="http://www.manicwave.com/blog/2010/03/01/that-feels-better-cocoa-hudson-and-running-green/">Hudson &#8211; Cocoa &#8211; Coverage Reporting blog post</a> from the other day.</p>
<p>I didn&#8217;t show the summary output that Cobertura displays in Hudson. &nbsp;It looked like this:</p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/coverage-before.png" border="0" alt="Coverage before cleanup" width="908" height="328" /></p>
<p>You&#8217;ll note (or I will do so for you) that there&#8217;s a variety of packages here (in the cocoa case, these are just subdirectories of the current workspace).</p>
<p>Notwithstanding the anemic percentages of coverage overall, outside of the &lt;default&gt; and CDGenerated packages, these are all third party components. &nbsp;While I&#8217;m extremely interested in knowing that they work correctly, it&#8217;s not on my radar to build out test coverage for each of these.&nbsp;</p>
<p>What I want is accurate reporting for the code that I write.</p>
<p>When we setup the gcovr build step in Hudson, the command looked like this:</p>
<p><span style="font-family: Courier; font-size: small;"><span style="font-family: Courier; font-size: small;"><span>/usr/local/bin/gcovr -r . -x -b -e /Developer &nbsp;1&gt; html/coverage.xml 2&gt;/dev/null</span></span></span></p>
<p>The -e /Developer command line argument instructs gcovr to <em>exclude</em><span>&nbsp;any files with names that match /Developer. &nbsp;The final config that I&#8217;m now working with is:</span></p>
<p><span><span style="font-family: Courier; font-size: small;"><span>/usr/local/bin/gcovr -r . -x -b -e /Developer -e &#8216;.*/UKKQueue/&#8217; -e &#8216;.*/DebugUtils/&#8217; -e &#8216;.*/Foundation/&#8217; -e &#8216;.*/UnitTesting/*&#8217; -e &#8216;.*/Third Party Sources/&#8217; -e &#8216;.*/ShortcutRecorder.framework/&#8217; 1&gt; html/coverage.xml 2&gt;/dev/null</span></span></span></p>
<p>Which is obtuse at best, but works. &nbsp;The &#8216;.*/xxx/&#8217; is necessary because the fully qualified path is processed by gcovr. &nbsp;In my case it would be /Users/jschilli/.hudson/jobs/Tickets-MASTER/workspace/&#8230;</p>
<p>The results now look like this:</p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/coverage-after.png" border="0" alt="coverage chart after tweaks" width="930" height="197" /></p>
<p><span>The absolute measure of coverage for each of the two remaining packages has not changed, but the information is now focused on the data that is most important to me.</span></p>
<p>With all of that said, the exclusions you choose to add are project specific. &nbsp;Hopefully this will help you hone the reporting to your liking.</p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.manicwave.com%2Fblog%2F2010%2F03%2F04%2Fsharpening-the-code-coverage-saw%2F&amp;linkname=Sharpening%20the%20code%20coverage%20saw">Share/Save</a>]]></content:encoded>
			<wfw:commentRss>http://www.manicwave.com/blog/2010/03/04/sharpening-the-code-coverage-saw/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>That feels better &#8211; Cocoa, Hudson and running green</title>
		<link>http://www.manicwave.com/blog/2010/03/01/that-feels-better-cocoa-hudson-and-running-green/</link>
		<comments>http://www.manicwave.com/blog/2010/03/01/that-feels-better-cocoa-hudson-and-running-green/#comments</comments>
		<pubDate>Tue, 02 Mar 2010 04:18:44 +0000</pubDate>
		<dc:creator>jschi</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Unit Testing]]></category>
		<category><![CDATA[cocoa]]></category>
		<category><![CDATA[xcode]]></category>

		<guid isPermaLink="false">http://www.manicwave.com/blog/?p=1770</guid>
		<description><![CDATA[&#160;
Continuous Integration
Continuous Integration (CI) has been around for a while now. Popularized in the java/ruby/[*lang*] communities, CI, when properly implemented promotes good code practices. &#160;CI alone won&#8217;t guarantee great code, but it helps support good behavior and in fact rewards users routinely and reliably.
&#160;
I&#8217;ve used Continuous Integration in many former lives &#8211; CI was essential [...]]]></description>
			<content:encoded><![CDATA[<p>&nbsp;</p>
<h2>Continuous Integration</h2>
<p>Continuous Integration (CI) has been around for a while now. Popularized in the java/ruby/[*lang*] communities, CI, when properly implemented promotes good code practices. &nbsp;CI alone won&#8217;t guarantee great code, but it helps support good behavior and in fact rewards users routinely and reliably.</p>
<p>&nbsp;</p>
<p>I&#8217;ve used Continuous Integration in many former lives &#8211; CI was essential on large geographically distributed teams &#8211; driving out incompatibilities in interface and implementation early and often.</p>
<p>My definition of a successful CI system and implementation are:</p>
<ol>
<li>Automated and unattended application build</li>
<li>Automated and unattended test execution</li>
</ol>
<p>Everything beyond that is gravy (or sugar).</p>
<h2>CI &amp; the indie</h2>
<p>When I released my first iPhone app, I was building the project in Xcode, switching to Finder and/or Terminal.app, compressing, copying and generally screwing up at every possible step. &nbsp;Although I&#8217;ve seen the benefits of automation multiple times, I was so busy getting this app out that I couldn&#8217;t see how I could take the time to write scripts. &nbsp;That airlock of paradox didn&#8217;t last long. &nbsp;I wrote a few scripts and every aspect of my build/sign/archive workflow was automated &#8211; when I ran the script.</p>
<p>&nbsp;</p>
<p>I repeated this exercise for my first Mac product &#8211; this time a hodge-podge of scripts to build the app, generate the help files, generate the sparkle appcast, release notes, upload, etc. &nbsp;I still use this script and it works great &#8211; when I run the script.</p>
<p>Although I&#8217;ve had great success with CI in the past, I wasn&#8217;t convinced that my one workunit indie shop could or would benefit from implementing CI. &nbsp;There were a few things that helped turn me around on this:</p>
<ol>
<li>The weakness of my script based build system continues to be the user centered part &#8211; me running the scripts. &nbsp;As I bounce from machine to machine, branch to branch, tucking frameworks away on one machine and not replicating them to another, [insert favorite 'in the heat of the battle' screwup here], issues might not emerge for some time.</li>
<li>Increased desire to capture metrics and data about my personal development process. &nbsp;I&#8217;m not implementing heavy weight metrics, but I understand absolutely that data can empower me to make decisions &#8211; test data, build data, coverage data.</li>
<li>Renewed belief that removing rote non value-adding activities from my routine will increase my effectiveness and throughput</li>
</ol>
<h2>Rule #1 of CI &#8211; Automated and Unattended Build</h2>
<p>When something changes, your CI should build the system to ensure that nothing has broken. &nbsp;If you&#8217;re in the zone and a failure pops up &#8211; easy to fix. &nbsp;If you find an issue weeks later &#8211; well we&#8217;ve all been there.</p>
<p>&nbsp;</p>
<p>CI is all about automating those rote tasks. &nbsp;It is important to emphasize both the automated aspects as well as the unattended aspects of CI. &nbsp;The only thing worse than no CI is CI that is broken and neglected. &nbsp;We&#8217;ll come back to this point in a bit.</p>
<h2>Hudson CI &amp; Cocoa</h2>
<p>There are several compelling CI solutions in the market -&nbsp;<a href="http://cruisecontrol.sourceforge.net/">CruiseControl</a>,&nbsp;<a href="https://hudson.dev.java.net/">Hudson</a> and scores of others in the opensource space. &nbsp;There are a spectrum of commercially available solutions as well including&nbsp;<a href="http://www.atlassian.com/software/bamboo/">Bamboo</a>. &nbsp;To my knowledge, there are no CI solutions that focus on the Cocoa space [just found <a href="http://bleepsoft.com/buildfactory/">BuildFactory</a> - haven't checked it out]. &nbsp;The good news is that most of these systems can run external processes &#8211; the by-product is good news for cocoa devs.</p>
<p>&nbsp;</p>
<p>Hudson seems to be the leading choice &#8211; it&#8217;s really straight forward to get the basics working. &nbsp;From there, incremental tweaks should get you up and running.</p>
<p><a href="http://www.atlassian.com/software/bamboo/"></a></p>
<h2>Preparing for the move</h2>
<p>I screwed up more than a few times getting my apps to build in Hudson. &nbsp;There are <a href="http://blog.jayway.com/2010/01/31/continuos-integration-for-xcode-projects/">more</a> than <a href="http://osx-ci.blogspot.com/2009_08_01_archive.html">a few pages</a> on <a href="http://nachbaur.com/blog/how-to-automate-your-iphone-app-builds-with-hudson">the web</a> that illustrate Cocoa/Hudson builds.</p>
<p>&nbsp;</p>
<p>My suggestion is to ensure that you can take a fresh cut of your project from your SCM system, check it out to a new directory and build it clean.</p>
<p>I would encourage you to do this outside of your normal dev tree &#8211; it&#8217;s surprising how easily a relative path will find its way into your xcode build settings.</p>
<ol>
<li>cd /tmp</li>
<li>checkout project to foobaz</li>
<li>build</li>
<li>if errors, rm -rf /tmp/foobaz, fix errors in main tree, checkin, goto #1</li>
</ol>
<p>This process should rid you of (many of) those hidden dependencies that will prevent a clean build once you&#8217;re executing inside of Hudson.</p>
<p>&nbsp;</p>
<p>Once you have a clean repeatable build &#8211; from your scm system &#8211; you should move on to getting hudson up and running.</p>
<h2>Setting up Hudson</h2>
<p>Installing Hudson is well documented on the net. &nbsp;The Hudson site includes&nbsp;<a href="http://wiki.hudson-ci.org/display/HUDSON/Installing+Hudson">installation instructions</a> that work well. &nbsp;There are several examples of cocoa specific sites &#8211; I started&nbsp;<a href="http://blog.jayway.com/2010/01/31/continuos-integration-for-xcode-projects/">here</a>.</p>
<p>&nbsp;</p>
<p>Because I have multiple targets setup in my Xcode project, I selected &#8216;This build is parameterized&#8217; and added some targets to choose from. &nbsp;Hudson will remember your last choice.</p>
<p><a href="http://blog.jayway.com/2010/01/31/continuos-integration-for-xcode-projects/"></a><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/Parameters.png" border="0" alt="Parameterized Build Settings" width="552" height="285" /></p>
<h2>Setting up SCM</h2>
<p>If you use Git,&nbsp;<a href="http://blog.jayway.com/author/christianhedin">Christian Hedin</a>&#8217;s article covers that configuration as well. &nbsp;The critical thing is to use either SCM polling or a post-commit-hook to invoke the build. &nbsp;Hudson will allow you to setup a time based build e.g. build every thirty minutes. &nbsp;The issue with that is that it will execute the build whether there are changes or not. &nbsp;Polling or post-commit-hooks will ensure that builds are invoked when change occurs.</p>
<p>&nbsp;</p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/scm-config1.png" border="0" alt="scm-config.png" width="551" height="398" /></p>
<p>You will note that I&#8217;ve elected to only build my master branch &#8211; by default, Hudson will checkout and build each branch that it finds in your Git repo. &nbsp;While I see this as advantageous (forward dev on master, branches for production release and bug fix), my branches haven&#8217;t gotten the Hudson CI/gcov/unit testing love that master has.</p>
<h2><span style="font-weight: normal; font-size: small;"><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/polling.png" border="0" alt="SCM Polling " width="555" height="194" /></span></h2>
<h2>Setting up your project</h2>
<p>In the interest of walking before I run, I want my Hudson build to checkout my updated code, compile my code, execute unit tests and capture any reporting output for test coverage and unit test failures. &nbsp;It turns out that most of this is already performed when I build my UnitTests target in my Xcode projects.</p>
<p>&nbsp;</p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/build-command.png" border="0" alt="Build Step" width="540" height="172" /></p>
<p><span style="font-weight: normal;">Click on build now &#8211; you can check the console to see the steps that Hudson is taking.</span></p>
<p><span style="font-weight: normal;">If the stars are aligned, you should have a successful build. &nbsp;If not, you&#8217;ll need to crawl through the console logs to determine where the failure occurred.</span></p>
<p>It is critical that you go back to your Xcode project/standalone build directory and correct mistakes there. &nbsp;Check in your changes and repeat. &nbsp;No one has to know how many times you repeat this cycle, but it&#8217;s critical to meet the spirit and law of Rule #1!</p>
<h2>Sugar</h2>
<p>Once the basic build is working you should add unit test reporting. &nbsp;If you have or are planning to run unit tests (Rule #2), download this <a href="http://github.com/ciryon/OCUnit2JUnit/blob/master/ocunit2junit.rb">ruby script</a>, install it in /usr/local/bin or the directory of your choice and change your build step to look like this:</p>
<p>&nbsp;</p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/Safari.png" border="0" alt="Safari.png" width="544" height="175" /></p>
<p>In the Post-build actions, configure Hudson to publish your test results.</p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/Safari2.png" border="0" alt="Safari.png" width="566" height="320" /></p>
<p>Trigger a build and you&#8217;ll now see a chart with the build results. &nbsp;As your test suite grows, you should see a trending graph with increased numbers of tests.</p>
<h2>Code Coverage</h2>
<p>Unit tests execution is what we&#8217;re after for Rule #2, but the number of tests as a key metric is easily misleading. &nbsp;I&#8217;ve seen a lot of cases where the same code is tested over and over again. &nbsp;Coverage is the key indicator!</p>
<p>&nbsp;</p>
<p>Download and install <a href="https://software.sandia.gov/trac/fast/export/2099/fast/trunk/scripts/gcovr">gcovr</a> and install it again in /usr/local/bin</p>
<p>Add the following as a new build step (after the xcodebuild step)</p>
<p>gcovr converts gcov data into a format parseable by Cobertura &#8211; a coverage analysis tool.</p>
<p>(See Tommy McLeod&#8217;s&nbsp;<a href="http://osx-ci.blogspot.com/2009_08_01_archive.html">blog post</a> here for some additional details)</p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/Safari3.png" border="0" alt="Safari.png" width="537" height="153" /></p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/cobertura.png" border="0" alt="Cobertura Configuration" width="546" height="320" /></p>
<p>Assuming you have gcov correctly working for your project (the subject of an as yet unwritten post), executing the build will result in some nice graphs.</p>
<p>You can now navigate through the coverage reports and see your annotated source code including what&#8217;s covered &#8211; and more importantly, what&#8217;s not. &nbsp;(There&#8217;s a one-line patch to gcovr detailed <a href="http://issues.hudson-ci.org/browse/HUDSON-5235">here</a> that allows Cobertura/Hudson to navigate into your code)</p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/coverage-graph.png" border="0" alt="Safari.png" width="567" height="302" /></p>
<p><p>[Edit 3/2/2010 - new example showing a real miss]</p>
<p>This example illustrates the value of visualizing test coverage &#8211; I had ~15 valid operations on a model class &#8211; I wrote this code from the spec &#8211; I erroneously interpreted running green on my unit tests meant all good. &nbsp;In fact, I had missed several cases &#8211; clearly identified here.</p>
<p>&nbsp;</p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/coverage-sample.png" border="0" alt="Safari.png" width="940" height="363" /></p>
<p>&nbsp;</p>
</p>
<h2>Finally</h2>
<p>Make some changes in your project, commit them to your SCM system and monitor the build. &nbsp;Make a test fail, introduce a compiler error and monitor the results.</p>
<p>&nbsp;</p>
<p>You want to be able to rely on your CI system to accurately report failures. &nbsp;If you have instability in the process, now is the time to grind through the issues.</p>
<p>You can install the Jabber notification plugin in Hudson, configure your jabber address (or that of a group chat if you&#8217;re working with multiple people) and Hudson will now inform you of build successes and failures. &nbsp;You can also configure email.</p>
<p>The compelling aspect of the Jabber plugin is that Hudson has a jabber bot that you can use to get status, trigger builds and more.</p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2010/03/Jabber.png" border="0" alt="Jabber Configuration" width="547" height="196" /></p>
<p>What&#8217;s left? &nbsp;There are a lot of different directions you can take Hudson now that the basics are in hand. &nbsp;I want to spend some more cycles getting better diagnostics when the build fails. &nbsp;Unit test failures are clearly reported. &nbsp;Compilation failures (forget to commit that new file to the build?) require spelunking through the console log. &nbsp;I also plan on moving my production builds to Hudson, but for now, getting that jabber notification that the build is clean is totally worth the time I&#8217;ve invested in setting this up.</p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.manicwave.com%2Fblog%2F2010%2F03%2F01%2Fthat-feels-better-cocoa-hudson-and-running-green%2F&amp;linkname=That%20feels%20better%20%26%238211%3B%20Cocoa%2C%20Hudson%20and%20running%20green">Share/Save</a>]]></content:encoded>
			<wfw:commentRss>http://www.manicwave.com/blog/2010/03/01/that-feels-better-cocoa-hudson-and-running-green/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Logitech &#8211; I want my day back</title>
		<link>http://www.manicwave.com/blog/2010/02/18/logitech-i-want-my-day-back/</link>
		<comments>http://www.manicwave.com/blog/2010/02/18/logitech-i-want-my-day-back/#comments</comments>
		<pubDate>Thu, 18 Feb 2010 22:33:07 +0000</pubDate>
		<dc:creator>jschi</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Tickets]]></category>
		<category><![CDATA[cocoa]]></category>

		<guid isPermaLink="false">http://www.manicwave.com/blog/?p=1754</guid>
		<description><![CDATA[Yesterday sucked from a productivity perspective. &#160;I&#8217;m deep into the development on Tickets 2.0 and spending a lot of time generating new versions of my Core Data based data model. &#160;This is a (normally) straight-forward exercise in Xcode &#8211; Design&#62;Data Model&#62;Add Model Version. &#160;The rub here is that this works fine on my Mac Book [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday sucked from a productivity perspective. &nbsp;I&#8217;m deep into the development on <a href="http://manicwave.com/products/tickets">Tickets 2.0</a> and spending a lot of time generating new versions of my Core Data based data model. &nbsp;This is a (normally) straight-forward exercise in Xcode &#8211; Design&gt;Data Model&gt;Add Model Version. &nbsp;The rub here is that this works fine on my Mac Book Pro, but failed without error on my Mac Pro. &nbsp;Yesterday, I&#8217;d had enough with git commit &amp;&amp; git push -&gt; switch to MBPro, make data model changes -&gt; git commit &amp;&amp; git push -&gt; back to Mac Pro -&nbsp;</p>
<p>I spent several hours trying to isolate the differences between the two setups &#8211; same project, different rev of Xcode. &nbsp;I down leveled my Xcode install on the Mac Pro, same result &#8211; now things are weird.</p>
<p>I moved /Developer to /Developer.old &#8211; clean install. &nbsp;No Love!</p>
<p>What I observed on the failing machine was that the versioned data model was being created in the .xcdatamodeld directory, but was not being added to the Xcode project.pbxproj file. &nbsp;Very Frustrating.</p>
<p>I grabbed Activity Monitor to watch the open files for Xcode to see if I could determine what was going on.</p>
<p>I noticed that <a href="http://www.stclairsoft.com/DefaultFolderX/index.html">DefaultFolderX</a> (DFX) had a scripting addition loaded into my Xcode process. &nbsp;I disabled DefaultFolderX and&nbsp;voil&agrave; I was able to add my versioned data model file.</p>
<p>Were it that this is the end of the story. &nbsp;I sent a note off to Jon Gotow at St. Clair Software with my observations. &nbsp;Jon quickly replied and asked if I was by chance using a Logitech mouse. &nbsp;I am. &nbsp;He further suggested that I look to see if&nbsp;/Library/ScriptingAdditions/LCC Scroll Enhancer Loader.osax was being loaded.</p>
<p>I reenabled DFX and saw that indeed LCC Scroll enhancer was loaded, with errors. &nbsp;I did a quick sudo rm&nbsp;/Library/ScriptingAdditions/LCC Scroll Enhancer Loader.osax, restarted Xcode and everything is working well again.</p>
<p>Many thanks to Jon for his quick and professional response. &nbsp;Logitech &#8211; my bill has been remitted.</p>
<p>&nbsp;</p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.manicwave.com%2Fblog%2F2010%2F02%2F18%2Flogitech-i-want-my-day-back%2F&amp;linkname=Logitech%20%26%238211%3B%20I%20want%20my%20day%20back">Share/Save</a>]]></content:encoded>
			<wfw:commentRss>http://www.manicwave.com/blog/2010/02/18/logitech-i-want-my-day-back/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Application Development Post Mortem</title>
		<link>http://www.manicwave.com/blog/2010/02/15/application-development-post-mortem/</link>
		<comments>http://www.manicwave.com/blog/2010/02/15/application-development-post-mortem/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 12:17:26 +0000</pubDate>
		<dc:creator>jschi</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>

		<guid isPermaLink="false">http://www.manicwave.com/blog/?p=1746</guid>
		<description><![CDATA[Were it that this was a post mortem for the recently released Tickets.app  
Rather, its a note that I need to do so.
Daniel Kennett of kennetnet software has put together a few nice post mortems, most recently this one detailing the development of an iPhone companion app.
Whether you put together a presentation, a video or [...]]]></description>
			<content:encoded><![CDATA[<p>Were it that this was a post mortem for the recently released Tickets.app <img src='http://manicwave.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Rather, its a note that I need to do so.</p>
<p>Daniel Kennett of <a href="http://www.kennettnet.co.uk/">kennetnet software</a> has put together a <a href="http://www.kennettnet.co.uk/blog/comments/clarus-1.0-postmortem/">few</a> <a href="http://www.kennettnet.co.uk/blog/comments/music_rescue_4.0_postmortem/">nice</a> post mortems, most recently this <a href="http://danielkennett.org/?p=487">one</a> detailing the development of an iPhone companion app.</p>
<p>Whether you put together a <a href="http://danielkennett.org/podcasts/iPhoneCompanionAppsSlides.pdf">presentation</a>, a <a href="http://danielkennett.org/podcasts/iPhoneCompanionAppsPodcast.mov">video</a> or simply scratch some notes in your moleskine, the act of analyzing your performance on a product development or contract development effort is a good one.</p>
<p>I keep a page in <a href="http://flyingmeat.com/voodoopad/">VoodooPad</a> for each development release and capture notes about what I could do better or differently the next time around.</p>
<p><a href="http://danielkennett.org/?p=487">iPhone Companion Apps: New Project to App Store in Two Months | Daniel Kennett</a>: &#8220;&#8221;</p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.manicwave.com%2Fblog%2F2010%2F02%2F15%2Fapplication-development-post-mortem%2F&amp;linkname=Application%20Development%20Post%20Mortem">Share/Save</a>]]></content:encoded>
			<wfw:commentRss>http://www.manicwave.com/blog/2010/02/15/application-development-post-mortem/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Unraveling the mysteries of NSSplitView &#8211; part 2</title>
		<link>http://www.manicwave.com/blog/2009/12/31/unraveling-the-mysteries-of-nssplitview-part-2/</link>
		<comments>http://www.manicwave.com/blog/2009/12/31/unraveling-the-mysteries-of-nssplitview-part-2/#comments</comments>
		<pubDate>Thu, 31 Dec 2009 16:38:07 +0000</pubDate>
		<dc:creator>jschi</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[cocoa]]></category>

		<guid isPermaLink="false">http://manicwave.com/blog/?p=1718</guid>
		<description><![CDATA[In part 1 of the series, we covered the very basics of NSSplitView.  We ended with a NSSplitView with two subviews.  We were able to constrain the minimum size of each.
In this part of the series, we are going to add collapsible subviews.
Collapsible subviews
There are several ways to support collapsible subviews.  The [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://manicwave.com/blog/2009/12/28/unraveling-the-mysteries-of-nssplitview-part-1/">part 1</a> of the series, we covered the very basics of NSSplitView.  We ended with a NSSplitView with two subviews.  We were able to constrain the minimum size of each.</p>
<p>In this part of the series, we are going to add collapsible subviews.</p>
<h2>Collapsible subviews</h2>
<p>There are several ways to support collapsible subviews.  The first is supported directly by NSSplitView.  As the user drags a divider to its minimum position, if subviews are collapsible, additional movement will result in the subview snapping shut.</p>
<p>We can support this behavior by adding the canCollapseSubview method.</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p1718code6'); return false;">View Code</a> OBJC</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p17186"><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code" id="p1718code6"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>splitView<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSSplitView_Class/"><span style="color: #400080;">NSSplitView</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>splitView canCollapseSubview<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/"><span style="color: #400080;">NSView</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>subview;
<span style="color: #002200;">&#123;</span>
    <a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/"><span style="color: #400080;">NSView</span></a><span style="color: #002200;">*</span> rightView <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>splitView subviews<span style="color: #002200;">&#93;</span> objectAtIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">1</span><span style="color: #002200;">&#93;</span>;
    NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@:%s returning %@&quot;</span>,<span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span>, _cmd, <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>subview isEqual<span style="color: #002200;">:</span>rightView<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>?<span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;YES&quot;</span><span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;NO&quot;</span><span style="color: #002200;">&#41;</span>;
    <span style="color: #a61390;">return</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>subview isEqual<span style="color: #002200;">:</span>rightView<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>

<p>Dragging the divider to the right most edge of the window will result in the right subview snapping shut.  The divider will still be show on the rightmost margin of the view.  This collapsing behavior is our first bit of good news.  When we collapse and uncollapse our right subviews, the layout is not munged as it was in part one when we effectively reduced the right subview width to zero.  We&#8217;ll use the observation later when we add programmatic collapsing.</p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2009/12/NSSplitView-Part1a1.png" border="0" alt="NSSplitView-Part1a.png" width="560" height="462" /><br />
<img src="http://manicwave.com/blog/wp-content/uploads/2009/12/NSSplitView-Part1a2.png" border="0" alt="NSSplitView-Part1a.png" width="560" height="462" /><br />
We can hide the divider when the right subview is collapsed.</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p1718code7'); return false;">View Code</a> OBJC</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p17187"><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code" id="p1718code7"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>splitView<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSSplitView_Class/"><span style="color: #400080;">NSSplitView</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>splitView shouldHideDividerAtIndex<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>NSInteger<span style="color: #002200;">&#41;</span>dividerIndex;
<span style="color: #002200;">&#123;</span>
    NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@:%s returning YES&quot;</span>,<span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span>, _cmd<span style="color: #002200;">&#41;</span>;
    <span style="color: #a61390;">return</span> <span style="color: #a61390;">YES</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>

<p><img src="http://manicwave.com/blog/wp-content/uploads/2009/12/NSSplitView-Part1a3.png" border="0" alt="NSSplitView-Part1a.png" width="560" height="462" /></p>
<p>If you keep you&#8217;re finger on the mouse while moving the divider, you can observe it collapse the right subview and then moving the divider back to the left &#8211; uncollapse it.</p>
<p>If you didn&#8217;t keep your finger on the mouse, the right view collapsed and there is no way now to get the view back.  Hovering over the right edge of the window won&#8217;t do it.  There aren&#8217;t any buttons to press, nothing to double click.</p>
<p>Before we fix this issue, change shouldHideDividerAtIndex back to returning NO.</p>
<p>We&#8217;ll add one more bit of goodness before we tackle programming collapsing.</p>
<h2>Double Click to collapse</h2>
<p>NSSplitViewDelegate includes an optional method shouldCollapseSubview:forDoubleClickOnDividerAtIndex: &#8211; it does its name suggests.  If we answer YES, double-clicking on the divider will collapse the right subview.  Double-clicking on the divider while the right subview is collapsed will uncollapse the right subview.</p>
<p>Here&#8217;s the implementation:</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p1718code8'); return false;">View Code</a> OBJC</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p17188"><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code" id="p1718code8"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>splitView<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSSplitView_Class/"><span style="color: #400080;">NSSplitView</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>splitView shouldCollapseSubview<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/"><span style="color: #400080;">NSView</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>subview forDoubleClickOnDividerAtIndex<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>NSInteger<span style="color: #002200;">&#41;</span>dividerIndex;
<span style="color: #002200;">&#123;</span>
    <a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/"><span style="color: #400080;">NSView</span></a><span style="color: #002200;">*</span> rightView <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>splitView subviews<span style="color: #002200;">&#93;</span> objectAtIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">1</span><span style="color: #002200;">&#93;</span>;
    NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@:%s returning %@&quot;</span>,<span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span>, _cmd, <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>subview isEqual<span style="color: #002200;">:</span>rightView<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>?<span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;YES&quot;</span><span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;NO&quot;</span><span style="color: #002200;">&#41;</span>;
    <span style="color: #a61390;">return</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>subview isEqual<span style="color: #002200;">:</span>rightView<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>

<p>Sweet!</p>
<h2>Programmatic Double Click</h2>
<p>Programmatic double-click will allow us to hook the action selector of a menu item, a toolbar button or other UI control to a method that will toggle the collapsed state of the collapsible subview.</p>
<p>First we&#8217;ll add a toolbar to our window to have a convenient place to put the toggle button.<br />
<img src="http://manicwave.com/blog/wp-content/uploads/2009/12/Interface-Builder.png" border="0" alt="Interface Builder.png" width="615" height="161" /></p>
<p>In MySplitViewController, we&#8217;ll add the logic to toggle right subview.</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p1718code9'); return false;">View Code</a> OBJC</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p17189"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code" id="p1718code9"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>toggleRightView<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">BOOL</span> rightViewCollapsed <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self mySplitView<span style="color: #002200;">&#93;</span> isSubviewCollapsed<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self mySplitView<span style="color: #002200;">&#93;</span> subviews<span style="color: #002200;">&#93;</span> objectAtIndex<span style="color: #002200;">:</span> <span style="color: #2400d9;">1</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
    NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@:%s toggleInspector isCollapsed: %@&quot;</span>,<span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span>, _cmd, rightViewCollapsed?<span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;YES&quot;</span><span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;NO&quot;</span><span style="color: #002200;">&#41;</span>;
	<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>rightViewCollapsed<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
		<span style="color: #002200;">&#91;</span>self uncollapseRightView<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span> <span style="color: #a61390;">else</span> <span style="color: #002200;">&#123;</span>
		<span style="color: #002200;">&#91;</span>self collapseRightView<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>collapseRightView
<span style="color: #002200;">&#123;</span>
&nbsp;
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/"><span style="color: #400080;">NSView</span></a> <span style="color: #002200;">*</span>right <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self mySplitView<span style="color: #002200;">&#93;</span> subviews<span style="color: #002200;">&#93;</span> objectAtIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">1</span><span style="color: #002200;">&#93;</span>;
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/"><span style="color: #400080;">NSView</span></a> <span style="color: #002200;">*</span>left  <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self mySplitView<span style="color: #002200;">&#93;</span> subviews<span style="color: #002200;">&#93;</span> objectAtIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">0</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">NSRect</span> leftFrame <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>left frame<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">NSRect</span> overallFrame <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self mySplitView<span style="color: #002200;">&#93;</span> frame<span style="color: #002200;">&#93;</span>; <span style="color: #11740a; font-style: italic;">//???</span>
    <span style="color: #002200;">&#91;</span>right setHidden<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>left setFrameSize<span style="color: #002200;">:</span>NSMakeSize<span style="color: #002200;">&#40;</span>overallFrame.size.width,leftFrame.size.height<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self mySplitView<span style="color: #002200;">&#93;</span> display<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>

<p>toggleRightView: is the public method that we&#8217;ll connect UI elements to.  It queries the NSSplitView to see if the right subview is collapsed.  If not, it calls collapseRightView otherwise, we&#8217;ll uncollapseRightView:.  The key element here is to ensure that the &#8216;collapsed&#8217; status of the right view is set correctly.  My first several attempts to make this work involved setting the frame width of the right view to 0.  NSSplitView did not answer YES to isSubviewCollapsed: under those circumstances.  Remember the observation earlier that when we snapped the right view closed and reopened it the view had not been mangled by autoresize logic?  That suggests that the view was never shrunk to zero width, but rather hidden.  I confirmed this with a <a href="http://www.fscript.org/">F-Script</a> session.</p>
<p>uncollapseRightView: is equally straight forward &#8211;</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p1718code10'); return false;">View Code</a> OBJC</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p171810"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="code" id="p1718code10"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>uncollapseRightView
<span style="color: #002200;">&#123;</span>
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/"><span style="color: #400080;">NSView</span></a> <span style="color: #002200;">*</span>left  <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self mySplitView<span style="color: #002200;">&#93;</span> subviews<span style="color: #002200;">&#93;</span> objectAtIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">0</span><span style="color: #002200;">&#93;</span>;
	<a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/"><span style="color: #400080;">NSView</span></a> <span style="color: #002200;">*</span>right <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self mySplitView<span style="color: #002200;">&#93;</span> subviews<span style="color: #002200;">&#93;</span> objectAtIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">1</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>right setHidden<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
&nbsp;
	CGFloat dividerThickness <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self mySplitView<span style="color: #002200;">&#93;</span> dividerThickness<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// get the different frames</span>
	<span style="color: #a61390;">NSRect</span> leftFrame <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>left frame<span style="color: #002200;">&#93;</span>;
	<span style="color: #a61390;">NSRect</span> rightFrame <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>right frame<span style="color: #002200;">&#93;</span>;
    <span style="color: #11740a; font-style: italic;">// Adjust left frame size</span>
	leftFrame.size.width <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span>leftFrame.size.width<span style="color: #002200;">-</span>rightFrame.size.width<span style="color: #002200;">-</span>dividerThickness<span style="color: #002200;">&#41;</span>;
	rightFrame.origin.x <span style="color: #002200;">=</span> leftFrame.size.width <span style="color: #002200;">+</span> dividerThickness;
	<span style="color: #002200;">&#91;</span>left setFrameSize<span style="color: #002200;">:</span>leftFrame.size<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>right setFrame<span style="color: #002200;">:</span>rightFrame<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self mySplitView<span style="color: #002200;">&#93;</span> display<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>

<p>The cool thing about all of this is that we&#8217;re not saving frame rects or adding additional data structures to hold this state.  I can assure you that my first several attempts to understand NSSplitView had loads of code to deal with view frames, collapse states, notifications to enable/disable view resizing etc.  It is true, at least in this case, that if you&#8217;re fighting the frameworks, there may be a more enlightened path awaiting discovery.</p>
<p>We can now go back and hide the divider when the right subview is collapsed.  The app should now look like this.</p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2009/12/NSSplitView-Part2.png" border="0" alt="NSSplitView-Part2.png" width="560" height="518" /></p>
<h2>Conclusion and Next Steps</h2>
<p>We&#8217;ve accomplished quite a bit.  I know, it&#8217;s hard coded to collapse only the right subview and only handles a single split, but the concepts at work are illustrated plainly.  The next few topics for future posts will include adding animated adjustments, controlling the effective drag area, customizing dividers and generalizing the solution.</p>
<p>The code for this segment can be downloaded here: <a href="http://manicwave.com/blog/support/NSSplitViewSamples/NSSplitView-Part2.zip">Part-2</a></p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.manicwave.com%2Fblog%2F2009%2F12%2F31%2Funraveling-the-mysteries-of-nssplitview-part-2%2F&amp;linkname=Unraveling%20the%20mysteries%20of%20NSSplitView%20%26%238211%3B%20part%202">Share/Save</a>]]></content:encoded>
			<wfw:commentRss>http://www.manicwave.com/blog/2009/12/31/unraveling-the-mysteries-of-nssplitview-part-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Unraveling the mysteries of NSSplitView &#8211; part 1</title>
		<link>http://www.manicwave.com/blog/2009/12/28/unraveling-the-mysteries-of-nssplitview-part-1/</link>
		<comments>http://www.manicwave.com/blog/2009/12/28/unraveling-the-mysteries-of-nssplitview-part-1/#comments</comments>
		<pubDate>Mon, 28 Dec 2009 19:35:17 +0000</pubDate>
		<dc:creator>jschi</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[cocoa]]></category>

		<guid isPermaLink="false">http://manicwave.com/blog/?p=1702</guid>
		<description><![CDATA[There are many examples of Mac applications that leverage split views to great effect.  Apple uses split views in many applications that we use every day &#8211; Mail.app, Preview.app, Xcode.app etc.  Many third parties use NSSplitView as well.  Gauging from the number of posts on the net, there is also a lot [...]]]></description>
			<content:encoded><![CDATA[<p>There are many examples of Mac applications that leverage split views to great effect.  Apple uses split views in many applications that we use every day &#8211; Mail.app, Preview.app, Xcode.app etc.  Many third parties use NSSplitView as well.  Gauging from the number of posts on the net, there is also a lot of confusion about how to accomplish the basics (or the expected) using the default NSSplitView class provided in the SDK.  This point is accentuated by the presence of several third party frameworks that provide these expected behaviors.</p>
<p>Pre-leopard behavior of NSSplitView gave rise to several of the third party frameworks.  In 10.5 Apple cleaned up the implementation of NSSplitView and ostensibly provides everything one needs to use split views effectively.</p>
<p>My experiences (and occasional frustrations) with third party frameworks led me to dig in and try to understand what Apple offers, how it works and how (if) I could package that up in a reusable form for use in my own applications.</p>
<h2>Requirements</h2>
<p>Everyone has there own pet list of requirements for a usable split view solution, but my list includes the following:</p>
<ul>
<li> collapsible subviews &#8211; A common UI capability today is a button or key combination that hides a subview</li>
<li> Intelligent subview resizing &#8211; There are a lot of documented issues with autoresizing Cocoa views &#8211; we need a splitview solution that doesn&#8217;t trash subviews when they are collapsed</li>
<li> Ability to specify additional drag areas for splitters</li>
<li> Ability to specify custom divider visuals</li>
<li> Sexy animation when toggling the visibility of subviews</li>
</ul>
<p>First, it&#8217;s worth looking at a few of the frameworks that are out there, what problems they solve and those that they don&#8217;t (from my perspective).</p>
<h2>RBSplitView</h2>
<p>The excellent RBSplitView emerged in 2004 in the pre-leopard days.  In addition to providing the runtime framework, RBSplitView includes an Interface Builder palette that supports IB modification of most of the desired behaviors, including divider selection, collapsible views, and min and max settings for view sizes.</p>
<p>RBSplitView also includes support for animating view adjustments such as collapse/uncollapse.</p>
<p>There are a long list of applications that use <a href="http://www.brockerhoff.net/src/rbs.html" target="_blank">RBSplitView</a> .</p>
<p>RBSplitView is, from my experiments, very solid code.  Capabilities such as toggling splits works, preserving subview layouts.</p>
<p>The primary issue with RBSplitView is that the animation used is pre Core Animation.  Running on my 8 core mac pro, this is not an issue, but it gets a bit jumpy on my MacBook Pro.  Further, by implementing the animations in the framework, RBSplitView limits ones ability to leverage a consistent CA based animation scheme throughout the application.</p>
<p>Bottom line &#8211; in a 10.6 world, is RBSplitView still the best solution?</p>
<h2>BWSplitView</h2>
<p>I have to say that I really want to like <a href="http://brandonwalkin.com/bwtoolkit/" target="_blank">BWSplitView</a> &#8211; Brandon Walkin&#8217;s framework that provides a modern NSSplitView based solution.  On the surface, it meets all of the requirements outlined above.  It is supported by a rich IB palette with a slew of conveniences.  Brandon&#8217;s site includes some great screencasts illustrating the promise of BWSplitView.</p>
<p>That said, I struggled in real world usage of BWSplitView.  Documented open issues around the splitter drag behavior created some showstopper issues for me.</p>
<p>In fact, it was my attempts to fix some of the BWSplitView issues that led me to explore how NSSplitView works.</p>
<h2>Digging in</h2>
<p>The canonical example of splitter view behavior is perhaps Mail.app.  Two splitters, a vertical split for the Mailboxes and main view.  The main view is horizontally split into the messages list and the message viewer.</p>
<p>To understand what NSSplitView offers out of the box, let&#8217;s build a sample app with a single splitter.  If we can understand what is going on with a single split view, we can generalize that as we add additional split views.</p>
<p>In order to verify the subview resizing challenges, one of our subviews will have several standard cocoa controls with autoresizing turned on.</p>
<p>The app looks like this:</p>
<p><img style="border: 0px initial initial;" src="http://manicwave.com/blog/wp-content/uploads/2009/12/NSSplitView-Part1-initial.png" border="0" alt="NSSplitView-Part1-initial.png" width="448" height="370" /></p>
<p>Dragging the divider all the way to the right and then back towards the middle quickly borks up the autoresizing behavior.</p>
<p><img style="border: 0px initial initial;" src="http://manicwave.com/blog/wp-content/uploads/2009/12/NSSplitView-Part1-borked.png" border="0" alt="NSSplitView-Part1-borked.png" width="667" height="491" /></p>
<p>To end part 1 of this exploration, let&#8217;s add minimum sizes for our split view.</p>
<p>We instantiate a new controller class, we&#8217;ll call it MySplitViewController (as it stands now, its just a delegate but we&#8217;ll be adding other functionality to it as we move along).</p>
<p>Instantiate an instance of this class in the XIB and hook the delegate outlet of the NSSplitView outlet to the new class.</p>
<p>There are a bunch of optional methods declared in the NSSplitViewDelegate &#8211; we&#8217;ll implement only two.  constrainMinCoordinate and constrainMaxCoordinate.  The documentation is sparse on the functionality of these methods, but the header file for NSSplitView does a pretty good job of laying out the basics.</p>
<p>constrainMin&#8230; and constrainMax are called repeatedly while the divider is being dragged.  In the example implementation, we&#8217;ll answer proposedMinimum+200 for the constrainMinCoordinate call, which in our example will have the effect of limiting the left subview to 200 pixels.  Judicious use of NSLog will show that the proposedMinimum will be 0 &#8212; we&#8217;re adding 200 and hence the minimum position of the divider will be 200 pixels.  When you begin having splitviews with more than two subviews, the concept is the same, but you are now responsible for determining which subview is being referenced.  In our example there is only one divider and its index will always be zero.</p>
<p>The constrainMaxCoordinate method works in a similar fashion.  The splitview sends in a proposedMaximumPosition that is the width of splitview &#8211; in this case, the entire width of the window.  We&#8217;ll answer with that value &#8211; 100 resulting in a maximum divider position of the window width &#8211; 100 pixels.</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p1702code12'); return false;">View Code</a> OBJC</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p170212"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="code" id="p1702code12"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> MySplitViewController
&nbsp;
<span style="color: #11740a; font-style: italic;">/*
 * Controls the minimum size of the left subview (or top subview in a horizonal NSSplitView)
 */</span>
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>CGFloat<span style="color: #002200;">&#41;</span>splitView<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSSplitView_Class/"><span style="color: #400080;">NSSplitView</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>splitView constrainMinCoordinate<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CGFloat<span style="color: #002200;">&#41;</span>proposedMinimumPosition ofSubviewAt<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>NSInteger<span style="color: #002200;">&#41;</span>dividerIndex;
<span style="color: #002200;">&#123;</span>
    NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@:%s proposedMinimum: %f&quot;</span>,<span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span>, _cmd, proposedMinimumPosition<span style="color: #002200;">&#41;</span>;
    <span style="color: #a61390;">return</span> proposedMinimumPosition <span style="color: #002200;">+</span> <span style="color: #2400d9;">200</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">/*
 * Controls the minimum size of the right subview (or lower subview in a horizonal NSSplitView)
 */</span>
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>CGFloat<span style="color: #002200;">&#41;</span>splitView<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSSplitView_Class/"><span style="color: #400080;">NSSplitView</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>splitView constrainMaxCoordinate<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CGFloat<span style="color: #002200;">&#41;</span>proposedMaximumPosition ofSubviewAt<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>NSInteger<span style="color: #002200;">&#41;</span>dividerIndex;
<span style="color: #002200;">&#123;</span>
    NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@:%s proposedMaximum: %f&quot;</span>,<span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span>, _cmd, proposedMaximumPosition<span style="color: #002200;">&#41;</span>;
    <span style="color: #a61390;">return</span> proposedMaximumPosition <span style="color: #002200;">-</span> <span style="color: #2400d9;">100</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>

<p><img src="http://manicwave.com/blog/wp-content/uploads/2009/12/left-size-constrained.png" border="0" alt="left-size-constrained.png" width="621" height="327" /></p>
<p><img src="http://manicwave.com/blog/wp-content/uploads/2009/12/right-size-constrained.png" border="0" alt="right-size-constrained.png" width="518" height="308" /></p>
<p>After compiling and running, we can now see that both the left and right subview are indeed constrained.  Although the 100 pixel extent of the right view does not prevent the view from looking terrible, it does prevent the autoresize funkiness of the first example.</p>
<h2>Conclusion and Next Steps</h2>
<p>We&#8217;ve only scratched the surface of NSSplitView.  We limited the complexity of our NSSplitView example to the simplest possible case and illustrated some of the challenges in using NSSplitView.  In the end, we were able to introduce a few delegate methods that exert additional control over the behavior of NSSplitView.</p>
<p>In the next article, we&#8217;ll add support for collapsible subviews and then add programatic collapsing.  Additional topics for future posts will cover adding animated adjustments, controlling the effective drag area, customizing dividers and generalizing the solution.</p>
<p>The code for this segment can be downloaded here: <a href="http://manicwave.com/blog/support/NSSplitViewSamples/NSSplitView-Part1.zip">Part 1 Sample Projects</a></p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.manicwave.com%2Fblog%2F2009%2F12%2F28%2Funraveling-the-mysteries-of-nssplitview-part-1%2F&amp;linkname=Unraveling%20the%20mysteries%20of%20NSSplitView%20%26%238211%3B%20part%201">Share/Save</a>]]></content:encoded>
			<wfw:commentRss>http://www.manicwave.com/blog/2009/12/28/unraveling-the-mysteries-of-nssplitview-part-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>git clone from Safari</title>
		<link>http://www.manicwave.com/blog/2009/12/11/git-clone-from-safari/</link>
		<comments>http://www.manicwave.com/blog/2009/12/11/git-clone-from-safari/#comments</comments>
		<pubDate>Sat, 12 Dec 2009 02:59:30 +0000</pubDate>
		<dc:creator>jschi</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[cocoa]]></category>

		<guid isPermaLink="false">http://manicwave.com/blog/?p=1677</guid>
		<description><![CDATA[It is often the late night exploration of code in the wild that gives rise to these cute little hacks.
With my wrist tiring of flipping between safari and terminal, the following was born.
Goal
 git clone the repository ref found in the system pasteboard
Scenario
When perusing gitHub, I&#8217;ll find something I want to check out.  I [...]]]></description>
			<content:encoded><![CDATA[<p>It is often the late night exploration of code in the wild that gives rise to these cute little hacks.</p>
<p>With my wrist tiring of flipping between safari and terminal, the following was born.</p>
<h2>Goal</h2>
<p> git clone the repository ref found in the system pasteboard</p>
<h2>Scenario</h2>
<p>When perusing <a href="http://github.com/">gitHub</a>, I&#8217;ll find something I want to check out.  I click on the &#8220;clone&#8221; button which copies the git reference to the clipboard.  I typically flip over to a terminal session, change directory to my favorite dumping grounds, and do a git clone Cmd-V enter.</p>
<p>Here&#8217;s a script that will do all of that.  The secret sauce is teaming this up with something like <a href="http://www.red-sweater.com/fastscripts/">FastScripts</a> (an excellent status bar accessory).</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p1677code14'); return false;">View Code</a> BASH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p167714"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code" id="p1677code14"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #007800;">REPO</span>=<span style="color: #000000; font-weight: bold;">`</span>pbpaste<span style="color: #000000; font-weight: bold;">`</span>
<span style="color: #007800;">DUMPDIR</span>=~<span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>extern
&nbsp;
<span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #007800;">$DUMPDIR</span> <span style="color: #000000; font-weight: bold;">&amp;&amp;</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>git<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span><span style="color: #c20cb9; font-weight: bold;">git</span> clone <span style="color: #007800;">$REPO</span>
<span style="color: #007800;">EXITCODE</span>=<span style="color: #007800;">$?</span>
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$EXITCODE</span>&quot;</span> <span style="color: #660033;">-ne</span> <span style="color: #ff0000;">&quot;0&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
	<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Download of <span style="color: #007800;">$REPO</span> failed: <span style="color: #007800;">$EXITCODE</span>&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>growlnotify <span style="color: #660033;">-p</span> <span style="color: #000000;">1</span> <span style="color: #ff0000;">&quot;Clone Failed&quot;</span>
<span style="color: #000000; font-weight: bold;">else</span>
	<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Download of <span style="color: #007800;">$REPO</span> successful&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>growlnotify <span style="color: #ff0000;">&quot;Clone Succeeded&quot;</span>
<span style="color: #000000; font-weight: bold;">fi</span></pre></td></tr></table></div>

<p>What&#8217;s happening here?</p>
<p>First we grab the repo reference from the pasteboard using pbpaste.  Then we cd to our dumping grounds, execute the git clone.  If it fails (because it&#8217;s already there, no access, etc) we use growlnotify to throw up the appropriate message.</p>
<p>I bind this script in ~/Library/Scripts/Applications/Safari and then use Cmd-Shift-C &#8211; so click to copy, Cmd-Shift-C to clone.</p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.manicwave.com%2Fblog%2F2009%2F12%2F11%2Fgit-clone-from-safari%2F&amp;linkname=git%20clone%20from%20Safari">Share/Save</a>]]></content:encoded>
			<wfw:commentRss>http://www.manicwave.com/blog/2009/12/11/git-clone-from-safari/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Defensive programming and the role of assertions</title>
		<link>http://www.manicwave.com/blog/2009/10/30/defensive-programming-and-the-role-of-assertions/</link>
		<comments>http://www.manicwave.com/blog/2009/10/30/defensive-programming-and-the-role-of-assertions/#comments</comments>
		<pubDate>Fri, 30 Oct 2009 14:45:49 +0000</pubDate>
		<dc:creator>jschi</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[cocoa]]></category>

		<guid isPermaLink="false">http://manicwave.com/blog/?p=1624</guid>
		<description><![CDATA[In Mike Ash&#8217;s excellent series &#8220;Friday Q&#038;A&#8221;, he recently wrote about defensive programming.
I&#8217;ve been tightening the screws on my first commercial Mac desktop app and reviewing my code for potential errors is front and center.  It&#8217;s fair to say that all developers should heed Mike&#8217;s advice.  I think its even more important (and [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://www.mikeash.com/?page=pyblog/">Mike Ash&#8217;s</a> excellent series &#8220;Friday Q&#038;A&#8221;, he recently wrote about <a href="http://www.mikeash.com/?page=pyblog/friday-qa-2009-10-09-defensive-programming.html">defensive programming</a>.</p>
<p>I&#8217;ve been tightening the screws on my first commercial Mac desktop app and reviewing my code for potential errors is front and center.  It&#8217;s fair to say that all developers should heed Mike&#8217;s advice.  I think its even more important (and fodder for a subsequent post) that indie developers heed this advice.  Programming solo in the echo chamber has its share of challenges &#8211; someone to look over your shoulder occasionally is not a bad thing.</p>
<p>One thing that has bitten me a few times as I&#8217;ve reswizzled my UI and cleaned up ivars is missing IB connections.  In Uli Kusterer excellent article on <a href="http://zathras.de/angelweb/blog-defensive-coding-in-objective-c.htm">Defensive coding in Objective-C</a> there is an excellent point about using NSAssert in your -awakeFromNib method to verify IB connections.</p>
<p>We&#8217;re getting there.  The issue is that I&#8217;ve been disappointed with the behavior of NSAssert in my work to date.  I will say up front that I may be missing something with NSAssert, but when I&#8217;m writing code and using assertions &#8211; I want a strong indication that something&#8217;s amiss.  Pouring through console logs to find a missing IB connection doesn&#8217;t do it for me.</p>
<p>Using the following in my awakeFromNib</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p1624code17'); return false;">View Code</a> OBJC</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p162417"><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code" id="p1624code17"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span> awakeFromNib
<span style="color: #002200;">&#123;</span>
    NSAssert<span style="color: #002200;">&#40;</span>button,<span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;IB connection for button is missing&quot;</span><span style="color: #002200;">&#41;</span>;
    NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;I'm the next line, but you'll never see me&quot;</span><span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>

<p>results in </p>
<pre>
*** Assertion failure in -[VerifyIBConnectionAppDelegate awakeFromNib], ..../VerifyIBConnectionAppDelegate.m:24
2009-10-30 10:20:45.824 VerifyIBConnection[35323:903] An uncaught exception was raised
2009-10-30 10:20:45.824 VerifyIBConnection[35323:903] IB connection for button is missing
2009-10-30 10:20:45.850 VerifyIBConnection[35323:903] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'IB connection for button is missing'
</pre>
<p>This is great.  The app is terminated, giving me strong feedback that something is amiss.</p>
<p>If however I move the assertions to -applicationDidFinishLaunching, I get</p>
<pre>
*** Assertion failure in -[VerifyIBConnectionAppDelegate applicationDidFinishLaunching:], .../VerifyIBConnectionAppDelegate.m:35
2009-10-30 10:23:28.746 VerifyIBConnection[35429:903] IB connection for button is missing
</pre>
<p>and &#8211; the app is still running.  The same assertions, in the same class, called at different points in the lifecycle have dramatically different results.  So now, in addition to coding defensively, I also need to ponder where I&#8217;m asserting what &#8211; or else.</p>
<p> Vincent Gable has a nice post on <a href="http://vgable.com/blog/2008/12/04/nsassert-considered-harmful/">NSAssert considered harmful</a> which brings out this and several other points.</p>
<p>So while you and I decide whether to use NSAssert or the more dramatic assert, I put together the following macro to reduce the verbosity of coding such assertions.</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p1624code18'); return false;">View Code</a> OBJC</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p162418"><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code" id="p1624code18"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">// NSAssert version</span>
<span style="color: #6e371a;">#define IBVERIFY(condition) NSAssert((condition), @&quot;IB Connection not established for %s&quot;, #condition)</span>
<span style="color: #11740a; font-style: italic;">// assert version</span>
<span style="color: #6e371a;">#define IBVERIFY(condition) assert((condition)!=nil &amp;&amp; &quot;IB Connection not established for:&quot; #condition)</span></pre></td></tr></table></div>

<p>The NSAssert version behaves as above.  The assert version results in </p>
<pre>
Assertion failed: ((button)!=nil &#038;&#038; "IB Connection not established for:" "button"), function -[VerifyIBConnectionAppDelegate awakeFromNib], file .../VerifyIBConnectionAppDelegate.m, line 25.
Program received signal:  “SIGABRT”.
</pre>
<p>Outside of the gratuitous additional double quotes (which I&#8217;m sure someone will point out how to eliminate) &#8211; this version has the comforting side effect of killing my app &#8211; wherever it&#8217;s invoked from.  I take comfort in getting that kind of direct feedback.</p>
<p>Should my opinion of NSAssert change, IBVERIFY can be easily retargeted to use such.</p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.manicwave.com%2Fblog%2F2009%2F10%2F30%2Fdefensive-programming-and-the-role-of-assertions%2F&amp;linkname=Defensive%20programming%20and%20the%20role%20of%20assertions">Share/Save</a>]]></content:encoded>
			<wfw:commentRss>http://www.manicwave.com/blog/2009/10/30/defensive-programming-and-the-role-of-assertions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>When DocSets disappear</title>
		<link>http://www.manicwave.com/blog/2009/08/18/when-docsets-disappear/</link>
		<comments>http://www.manicwave.com/blog/2009/08/18/when-docsets-disappear/#comments</comments>
		<pubDate>Tue, 18 Aug 2009 11:21:23 +0000</pubDate>
		<dc:creator>jschi</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[cocoa]]></category>
		<category><![CDATA[xcode]]></category>

		<guid isPermaLink="false">http://manicwave.com/blog/?p=1529</guid>
		<description><![CDATA[I have two OS X development machines, a beefy Mac Pro and a Mac Book Pro (MBP).
I recently repaved the MBP and reestablished my development toolchain.
When looking at Documentation on the MBP, I noticed that the &#8220;Doc Sets&#8221; pane displayed (as expected).
On my Mac Pro, no love.  I&#8217;m not sure how it disappeared, but [...]]]></description>
			<content:encoded><![CDATA[<p>I have two OS X development machines, a beefy Mac Pro and a Mac Book Pro (MBP).</p>
<p>I recently repaved the MBP and reestablished my development toolchain.</p>
<p>When looking at Documentation on the MBP, I noticed that the &#8220;Doc Sets&#8221; pane displayed (as expected).</p>
<p>On my Mac Pro, no love.  I&#8217;m not sure how it disappeared, but after several minutes of clicking around with no luck, I got down to business.</p>
<p>A quick scan of <code>defaults read com.apple.Xcode</code> revealed a whole bunch of potential settings.</p>
<p>On my MBP I saved off a copy of my defaults and then resized the Doc Sets pane.</p>
<p>Another snapshot and a diff revealed a property with the geometry for the Doc Sets window.</p>

<div class="wp_codebox_msgheader"><span class="right"><sup><a href="http://www.ericbess.com/ericblog/2008/03/03/wp-codebox/#examples" target="_blank" title="WP-CodeBox HowTo?"><span style="color: #99cc00">?</span></a></sup></span><span class="left"><a href="javascript:;" onclick="javascript:showCodeTxt('p1529code20'); return false;">View Code</a> BASH</span><div class="codebox_clear"></div></div><div class="wp_codebox"><table><tr id="p152920"><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code" id="p1529code20"><pre class="bash" style="font-family:monospace;">quant:jschilli$ defaults <span style="color: #c20cb9; font-weight: bold;">read</span> com.apple.Xcode <span style="color: #ff0000;">&quot;NSSplitView Subview Frames DocSetsAndSearchResultsSplitView&quot;</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span>
    <span style="color: #ff0000;">&quot;0.000000, 0.000000, 0.000000, 1249.000000, NO&quot;</span>,
    <span style="color: #ff0000;">&quot;0.000000, 0.000000, 1869.000000, 1249.000000, NO&quot;</span>
<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></td></tr></table></div>

<p>That&#8217;s an awful lot of zeros &#8211; and very different from the MBP.</p>
<p>I closed XCode on the Mac Pro, and deleted the key.</p>
<p><code>defaults delete com.apple.Xcode "NSSplitView Subview Frames DocSetsAndSearchResultsSplitView"</code></p>
<p>Fired up XCode and low and behold &#8211; Doc Sets now display again.</p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.manicwave.com%2Fblog%2F2009%2F08%2F18%2Fwhen-docsets-disappear%2F&amp;linkname=When%20DocSets%20disappear">Share/Save</a>]]></content:encoded>
			<wfw:commentRss>http://www.manicwave.com/blog/2009/08/18/when-docsets-disappear/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
