<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Pioneering Software</title>
    <link>http://blog.pioneeringsoftware.co.uk</link>
    
    <language>en-us</language>
    <ttl>40</ttl>
    <description>innovation | quality | care</description>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/PioneeringSoftware" /><feedburner:info uri="pioneeringsoftware" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
      <title>Import CSV files in Rails 3</title>
      <description>&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Comma-separated_values"&gt;CSV&lt;/a&gt; is a ubiquitous importing and exporting format for tables of information conforming to row-column layout. Lines correspond to rows. On each line, commas separate values under each column; hence Comma-Separated Values. Values between commas define table-cell contents, strings or numbers. The format is relatively flexible, relatively easy for machines and even humans to read and write.&lt;/p&gt;

&lt;p&gt;In terms of &lt;a href="http://www.agilemodeling.com/artifacts/userStory.htm"&gt;user stories&lt;/a&gt;, it answers the following requirement.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;As a: database maintainer&lt;/p&gt;

&lt;p&gt;I want to: import information from external files, particularly Comma-Separated Value files where rows appear on each line and columns within each row have comma delimiters&lt;/p&gt;

&lt;p&gt;So that I can: select columns (and rows) from the CSV files and merge these to create other new pieces of information.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Question is, How do you import CSV files in Rails 3. This article attempts an answer, or at least part of an answer, enough perhaps to point you in the right direction. You can find the sources &lt;a href="http://github.com/royratcliffe/import-csv-files-in-rails-3"&gt;here at GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Prerequisites&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Rails 3&lt;/li&gt;
&lt;li&gt;FasterCSV gem (Ruby parlance for an &lt;em&gt;installable package&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;JQuery&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Why?&lt;/h3&gt;

&lt;p&gt;That is an important question. Has this sort of thing &lt;strong&gt;not&lt;/strong&gt; been done before, many times? Well, yes. This is nothing new. But it does offer a fresh look at the subject, especially in the light of the upcoming new version of Rails and with preference for jQuery over Prototype for Rails&amp;#8217; JavaScript library. If you like, consider this a scenic voyage into Rails 3 and jQuery. The seas are fairly calm even though only at Beta.&lt;/p&gt;

&lt;h3&gt;Check your versions&lt;/h3&gt;

&lt;p&gt;Entering &lt;code&gt;rails -v&lt;/code&gt; on the command line reports,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Rails 3.0.0.beta4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At the time of writing this version is the latest prerelease. Install it using &lt;code&gt;sudo gem install rails --pre&lt;/code&gt;; option &lt;code&gt;pre&lt;/code&gt; allows installation of prerelease versions, i.e. betas.&lt;/p&gt;

&lt;p&gt;Doing similarly for &lt;a href="http://rubygems.org/"&gt;RubyGems&lt;/a&gt; using &lt;code&gt;gem -v&lt;/code&gt; gives,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;1.3.7
&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;Test-driven approach&lt;/h1&gt;

&lt;p&gt;Begin with a new Rails application.&lt;/p&gt;

&lt;p&gt;The command to create a new application has changed since Rails 2. The Rails project now brings together the various disparate scripts and generators under one umbrella, so to speak. New applications now appear when you ask,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rails new APP_PATH
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;where &lt;code&gt;APP_PATH&lt;/code&gt; specifies where your Rails application tree will reside on the local file system. The exact name does not actually matter too much. Although the name &lt;em&gt;does&lt;/em&gt; become part of the application proper: it names the application module, and appears in the cookie store key; but you can change these later if you wish.&lt;/p&gt;

&lt;p&gt;I will give it a long name. The following command creates a new folder called &lt;code&gt;import-csv-files-in-rails-3&lt;/code&gt;. Rails fills it with basic structure and content, enough to get you started.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rails new import-csv-files-in-rails-3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The application is ready to run already. It does not do anything yet, of course. However, you can launch the server and access the application at &lt;a href="http://localhost:3000"&gt;localhost:3000&lt;/a&gt;. Note, syntax for launching a local server has also changed in Rails 3. You no longer enter &lt;code&gt;script/server&lt;/code&gt;; it is now in the slightly-less wordy form,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rails s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;s&lt;/code&gt; for server, naturally.&lt;/p&gt;

&lt;h2&gt;Test bed&lt;/h2&gt;

&lt;p&gt;As a simple starting point, imagine a Rails application comprising &lt;em&gt;people&lt;/em&gt; and &lt;em&gt;places&lt;/em&gt;. People have a first and last name; places have an address. Let the application&amp;#8217;s database store these two entities, along with these attributes. Person entity with first and last name attributes, both strings. Place entity with address attribute, a simple string for now.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://images.pioneeringsoftware.co.uk/Importing%20CSV%20files%20in%20Rails%203.png" title="Entity-Relationship diagram; Person with two columns, first_name and last_name; Place with one column, address" alt="Entity-Relationship diagram" /&gt;&lt;/p&gt;

&lt;p&gt;Generating the basic Rails scaffolding is very easy. Just two commands gives us the entities and their properties, together with corresponding controllers and views to access them via HTML and RESTful XML. &lt;code&gt;g&lt;/code&gt; is short for &lt;em&gt;generate&lt;/em&gt; in the following two commands.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rails g scaffold person first_name:string last_name:string
rails g scaffold place address:string
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Migrate the database using &lt;code&gt;rake db:migrate&lt;/code&gt; to update the database schema. By default Rails will use &lt;a href="http://www.sqlite.org/"&gt;SQLite&lt;/a&gt;. Good enough for this exercise. You can then launch a local server to access people at &lt;a href="http://localhost:3000/people"&gt;localhost:3000/people&lt;/a&gt; and places at &lt;a href="http://localhost:3000/places"&gt;localhost:3000/places&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once set up, the goal will become to import people and place information using CSV files. This is the real challenge.&lt;/p&gt;

&lt;h2&gt;Test import&lt;/h2&gt;

&lt;p&gt;One more thing. You may not have a list of people and places handy. But a CSV file or two will definitely be very useful for testing. So just for testing purposes, let us write a script to generate a file.&lt;/p&gt;

&lt;p&gt;See below. Copy this and run it to generate some CSV files comprised of random words using &lt;a href="http://dancroak.com/"&gt;Dan Croak&lt;/a&gt;&amp;#8217;s &lt;a href="http://github.com/dancroak/webster"&gt;Webster&lt;/a&gt; gem, a package for randomly generating short non-offensive words. You will need to install the gem using &lt;code&gt;sudo gem install webster&lt;/code&gt;. Do the same for &lt;code&gt;fastercsv&lt;/code&gt; if you haven&amp;#8217;t already.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt;!/usr/bin/env ruby
&lt;/span&gt;
&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;optparse&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;ostruct&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

options &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;OpenStruct&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;
options&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;rows &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;10&lt;/span&gt;
options&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;columns &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;10&lt;/span&gt;
&lt;span class="support support_class support_class_ruby"&gt;OptionParser&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;opts&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
  opts&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;on&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;-r&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;--rows [INTEGER]&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;Number of rows&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Integer&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;x&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
    options&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;rows &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; x
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
  opts&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;on&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;-c&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;--columns [INTEGER]&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;Number of columns&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Integer&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;x&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
    options&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;columns &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; x
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;parse!

&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;rubygems&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;fastercsv&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;webster&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

webster &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;Webster&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;

&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ARGV&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;/dev/stdout&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;ARGV&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;empty?
&lt;span class="support support_class support_class_ruby"&gt;ARGV&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;file_name&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
  &lt;span class="support support_class support_class_ruby"&gt;FasterCSV&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;open&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;file_name&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;w&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;csv&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
    options&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;rows&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;times &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;row_index&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
      row &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[]&lt;/span&gt;
      options&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;columns&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;times &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;column_index&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
        row &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;&amp;lt;&amp;lt;&lt;/span&gt; webster&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;random_word
      &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
      csv &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;&amp;lt;&amp;lt;&lt;/span&gt; row
    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You will find this script &lt;a href="http://gist.github.com/474564#file_gen_webster_csv.rb"&gt;here as a Gist&lt;/a&gt;. Download it, make it executable and run using,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;./gen-webster-csv.rb test.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;Two-stage process: upload and merge&lt;/h1&gt;

&lt;p&gt;For simplicity, the application design will take a two-stage approach to importing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stage 1: upload&lt;/li&gt;
&lt;li&gt;Stage 2: merge&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Here, &lt;em&gt;upload&lt;/em&gt; refers to the action of receiving a raw CSV file from a browser and storing it somewhere within the application&amp;#8217;s database or otherwise readily-accessible place. &lt;em&gt;Merge&lt;/em&gt; refers to the action of moving selected columns to the database proper. In a real application, you might choose to fold both stages into one action. But for this exercise, we make them distinct. The first stage takes a CSV file and stores it. The second stage lets the user pick out one or more columns and &lt;strong&gt;choose&lt;/strong&gt; where to move the data: to people or places within the database. This second stage does have an advantage: it allows the user to see the imported information and select and deselect columns. Only selected columns will merge and become useful to the app.&lt;/p&gt;

&lt;h2&gt;Uploading, stage 1&lt;/h2&gt;

&lt;p&gt;First upload the CSV file, then store it.&lt;/p&gt;

&lt;h3&gt;Uploading files&lt;/h3&gt;

&lt;p&gt;Uploading a file is straightforward. Just add a form with a &amp;#8216;file field.&amp;#8217; When submitted, the form will send a &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html"&gt;POST&lt;/a&gt; request with the file contents attached.&lt;/p&gt;

&lt;p&gt;Create a CSV controller with an &lt;em&gt;import&lt;/em&gt; action.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ rails g controller csv import
      create  app/controllers/csv_controller.rb
       route  get "csv/import"
      invoke  erb
      create    app/views/csv
      create    app/views/csv/import.html.erb
      invoke  test_unit
      create    test/functional/csv_controller_test.rb
      invoke  helper
      create    app/helpers/csv_helper.rb
      invoke    test_unit
      create      test/unit/helpers/csv_helper_test.rb
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice, Rails creates a default controller, a &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html"&gt;GET&lt;/a&gt;-request route for the action, an &lt;a href="http://stdlib.rubyonrails.org/libdoc/erb/rdoc/classes/ERB.html"&gt;ERB&lt;/a&gt;-based view for the action along with test and helper stubs. Hence, when an external browser sends the application a GET request at &lt;code&gt;csv/import&lt;/code&gt;, Rails will match the route, find the ERB template, render the &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html"&gt;HTML&lt;/a&gt; response and reply. The &amp;#8216;view&amp;#8217; only needs to incorporate a standard HTML form which the browser will promptly display.&lt;/p&gt;

&lt;p&gt;Navigate to the import view, &lt;code&gt;app/views/csv/import.html.erb&lt;/code&gt; and add the HTML form, as follows.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="text text_html text_html_ruby"&gt;&lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="support support_function support_function_viewhelpers support_function_viewhelpers_rails"&gt;form_for&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;upload&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;html&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;multipart&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;true&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;f&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%=&lt;/span&gt; f&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="support support_function support_function_viewhelpers support_function_viewhelpers_rails"&gt;file_field&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;csv&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%=&lt;/span&gt; f&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="support support_function support_function_viewhelpers support_function_viewhelpers_rails"&gt;submit&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Upload&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;disable_with&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;Uploading...&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt; makes this very easy to type. Type &lt;code&gt;ff&lt;/code&gt; then press Tab to lay out the basic &lt;code&gt;form_for&lt;/code&gt; skeleton. Use &lt;code&gt;:&lt;/code&gt; then Tab to add a key-value pair of the form &lt;code&gt;:key =&amp;gt; "value"&lt;/code&gt;; type the key, press Tab and type the value. Tab again moves you to the comma delimiter, and so on.&lt;/p&gt;

&lt;p&gt;The most important part of the form is the &lt;code&gt;:html =&amp;gt; { :multipart =&amp;gt; true }&lt;/code&gt; option. This ensures that the POST-request parameters will contain the actual file contents. The request will contain a parameter called &lt;code&gt;upload&lt;/code&gt; (as defined by the first argument of the &lt;code&gt;form_for&lt;/code&gt;) which maps to a dictionary with key &lt;code&gt;csv&lt;/code&gt; mapping to a &lt;code&gt;File&lt;/code&gt; object which the application can parse to extract the uploaded CSV. Within the Rails controller for handling the POST request, the &lt;code&gt;File&lt;/code&gt; object will be found by accessing &lt;code&gt;params[:upload][:csv]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When the user fills in the form and clicks Upload, the browser will send a POST request containing the CSV-file contents. The Rails application needs to respond. Hence it needs a &lt;em&gt;route&lt;/em&gt; describing how the request and URL path translates to controller and action. Under Rails 3, this becomes very easy. Just add the following line to your &lt;code&gt;config/routes.rb&lt;/code&gt;. Here, &lt;code&gt;csv/import&lt;/code&gt; specifies the URL path; while &lt;code&gt;csv#upload&lt;/code&gt; specifies controller and action respectively. When Rails routing sees a POST at that URL path, it will invoke method &lt;code&gt;upload&lt;/code&gt; of the CSV controller, class &lt;code&gt;CsvController&lt;/code&gt;.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;  post &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;csv/import&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;csv#upload&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This route needs a corresponding action for the CSV controller. Add this method to your &lt;code&gt;CsvController&lt;/code&gt; class, source at &lt;code&gt;app/controllers/csv_controller.rb&lt;/code&gt; under the application&amp;#8217;s source tree.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;upload&lt;/span&gt;&lt;/span&gt;
&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; While under development, just respond by rendering some in-line text.
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; Send back the request parameters in JSON (JavaScript Object Notation)
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; format, i.e. something reasonably easy to parse with the human eye.
&lt;/span&gt;    render &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;text&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; params&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_json
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h3&gt;Store the CSV contents&lt;/h3&gt;

&lt;p&gt;Where to store the imported CSV information? We &lt;em&gt;could&lt;/em&gt; store the CSV file verbatim somewhere on a local file system; that would be typical. But let us assume that there is no local file system such as for web applications &lt;a href="http://en.wikipedia.org/wiki/Cloud_computing"&gt;running in the cloud&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Storing the CSV temporarily in some kind of document-based key-value store like &lt;a href="http://www.mongodb.org/"&gt;MongoDB&lt;/a&gt; or &lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt; would be another alternative. It would live outside the database. The application database would contain a link to the external &amp;#8216;document&amp;#8217; and read it when required. But no. For now, let us keep it fairly simple. Instead, we will conceptually map the CSV to a simple data model and store the CSV information within the database itself. See data model below.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://images.pioneeringsoftware.co.uk/Import%20tables%20and%20cells.png" title="Import tables and cells" alt="Import tables and cells" /&gt;&lt;/p&gt;

&lt;p&gt;ImportTables have many ImportCells; ImportCells have row and column indices, string contents and belong to one particular ImportTable. The database will index the cells by their &lt;code&gt;import_table_id&lt;/code&gt; (back-reference to the owning import table) in order to pull all cells belonging to a table quickly from the database into main memory.&lt;/p&gt;

&lt;p&gt;Implementing this model in Rails proves relatively easy.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ rails g scaffold import_table original_path:string
      invoke  active_record
      create    db/migrate/20100715123031_create_import_tables.rb
      create    app/models/import_table.rb
      invoke    test_unit
      create      test/unit/import_table_test.rb
      create      test/fixtures/import_tables.yml
       route  resources :import_tables
      invoke  scaffold_controller
      create    app/controllers/import_tables_controller.rb
      invoke    erb
      create      app/views/import_tables
      create      app/views/import_tables/index.html.erb
      create      app/views/import_tables/edit.html.erb
      create      app/views/import_tables/show.html.erb
      create      app/views/import_tables/new.html.erb
      create      app/views/import_tables/_form.html.erb
      invoke    test_unit
      create      test/functional/import_tables_controller_test.rb
      invoke    helper
      create      app/helpers/import_tables_helper.rb
      invoke      test_unit
      create        test/unit/helpers/import_tables_helper_test.rb
      invoke  stylesheets
   identical    public/stylesheets/scaffold.css
$ rails g model import_cell import_table_id:integer row_index:integer column_index:integer contents:string
      invoke  active_record
      create    db/migrate/20100715123207_create_import_cells.rb
      create    app/models/import_cell.rb
      invoke    test_unit
      create      test/unit/import_cell_test.rb
      create      test/fixtures/import_cells.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To establish the one-to-many association between import table and import cell, add two new lines: a &lt;code&gt;has_many&lt;/code&gt; and a &lt;code&gt;belongs_to&lt;/code&gt;. Your &lt;code&gt;app/models/import_table.rb&lt;/code&gt; and &lt;code&gt;app/models/import_cell.rb&lt;/code&gt; should look like this. The import table&amp;#8217;s &lt;code&gt;:dependent =&amp;gt; :destroy&lt;/code&gt; option instructs Rails to delete its cells when you delete a table.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;ImportTable&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  has_many &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;import_cells&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;dependent&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;destroy&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;




&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;ImportCell&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  belongs_to &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;import_table&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;For speedy performance, you also need to add an index for the import cells. Generate a migration.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ rails g migration add_index_for_import_cells
      invoke  active_record
      create    db/migrate/20100715124738_add_index_for_import_cells.rb
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then edit the newly-created migration code, adding instructions to add and remove an index. Without this, whenever you ask Rails for a table&amp;#8217;s cells using &lt;code&gt;table.import_cells&lt;/code&gt; where &lt;code&gt;table&lt;/code&gt; references an instance of &lt;code&gt;ImportTable&lt;/code&gt;, the answer will arrive but slowly because the database cannot quickly lookup the cells given a particular &lt;code&gt;import_table_id&lt;/code&gt; which uniquely identifies the import table. Note also, the index is non-unique. The answers to &lt;code&gt;table.import_cells&lt;/code&gt; which navigate the one-to-many table-to-cell association is an &lt;em&gt;array&lt;/em&gt; of many &lt;code&gt;ImportCell&lt;/code&gt; instances.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;AddIndexForImportCells&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Migration&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;self.up&lt;/span&gt;&lt;/span&gt;
    add_index &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;import_cells&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;import_table_id&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;self.down&lt;/span&gt;&lt;/span&gt;
    remove_index &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;import_cells&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;column&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;import_table_id&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Finally, do not forget to run the &amp;#8216;up&amp;#8217; migrations to upgrade your database schema. Run &lt;code&gt;rake db:migrate&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Upload action&lt;/h3&gt;

&lt;p&gt;Thus far, we have the means to &lt;em&gt;store&lt;/em&gt; CSV table information, but do not yet have the code in place to parse the uploaded CSV into import tables. The &lt;code&gt;CsvController&lt;/code&gt; method below uses the &lt;code&gt;FasterCSV&lt;/code&gt; gem to parse the incoming file. Edit your &lt;code&gt;app/controllers/csv_controller.rb&lt;/code&gt; source to look like this.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;fastercsv&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_rails meta_rails_controller"&gt;&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;CsvController&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ApplicationController&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;import&lt;/span&gt;&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;upload&lt;/span&gt;&lt;/span&gt;
    table &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;ImportTable&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;original_path&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; params&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;upload&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;][&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;csv&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;original_path
    row_index &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;
    &lt;span class="support support_class support_class_ruby"&gt;FasterCSV&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;parse&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;params&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;upload&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;][&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;csv&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;cells&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
      column_index &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;
      cells&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;cell&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
        table&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;import_cells&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;build &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;column_index&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; column_index&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;row_index&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; row_index&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;contents&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; cell
        column_index &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;+=&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;
      &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
      row_index &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;+=&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
    table&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;save
    &lt;span class="support support_function support_function_actionpack support_function_actionpack_rails"&gt;redirect_to&lt;/span&gt; import_table_path&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;table&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The code constructs a new import table passing the original file&amp;#8217;s path; &lt;code&gt;original_path&lt;/code&gt; is a column in the &lt;code&gt;ImportTable&lt;/code&gt; database table. The &lt;code&gt;upload&lt;/code&gt; method uses the &lt;code&gt;build&lt;/code&gt; method on the to-many association between table and cell in order to build new cells and attach them to the table. After parsing, the method saves the table then redirects the user to its &amp;#8216;show&amp;#8217; page so that the user can see the newly-imported data.&lt;/p&gt;

&lt;p&gt;Add the following to &lt;code&gt;Gemfile&lt;/code&gt; for Rails 3. This tells Rails to prepare the package for import. Without this you &lt;em&gt;cannot&lt;/em&gt; do a &lt;code&gt;require 'fastercsv'&lt;/code&gt;. &lt;code&gt;Gemfile&lt;/code&gt; appears in the root directory of the application folder. Although, if you are using TextMate on a Mac, locating any file no matter where it lives is very quick using Command+T then start typing the name. A list of matches starts to appear. Just pick the one you want.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gem 'fastercsv'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then to view the uploaded table, add these lines to your &lt;code&gt;ImportTablesController&lt;/code&gt;&amp;#8217;s &lt;code&gt;show&lt;/code&gt; method.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_controller"&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;import_cells&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;import_table&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;import_cells
    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;row_index_max&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;import_cells&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;map &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;cell&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; cell&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;row_index &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;max
    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;column_index_max&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;import_cells&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;map &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;cell&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; cell&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;column_index &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;max
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Add the lines above after finding the import table, i.e. after &lt;code&gt;@import_table = ImportTable.find(params[:id])&lt;/code&gt;. Then display cell contents in &lt;code&gt;app/views/import_tables/show.html.erb&lt;/code&gt; by adding this piece of Ruby-embedded HTML.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="text text_html text_html_ruby"&gt;&lt;span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_begin punctuation_definition_tag_begin_html"&gt;&amp;lt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html"&gt;table&lt;/span&gt; &lt;span class="entity entity_other entity_other_attribute-name entity_other_attribute-name_html"&gt;border&lt;/span&gt;=&lt;span class="string string_quoted string_quoted_double string_quoted_double_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_html"&gt;"&lt;/span&gt;1&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_html"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_other entity_other_attribute-name entity_other_attribute-name_html"&gt;cellspacing&lt;/span&gt;=&lt;span class="string string_quoted string_quoted_double string_quoted_double_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_html"&gt;"&lt;/span&gt;1&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_html"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_other entity_other_attribute-name entity_other_attribute-name_html"&gt;cellpadding&lt;/span&gt;=&lt;span class="string string_quoted string_quoted_double string_quoted_double_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_html"&gt;"&lt;/span&gt;1&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_html"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_end punctuation_definition_tag_end_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;upto&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;row_index_max&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;row_index&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; row &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;import_cells&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;select &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;cell&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; cell&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;row_index &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;==&lt;/span&gt; row_index &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_begin punctuation_definition_tag_begin_html"&gt;&amp;lt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html"&gt;tr&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_end punctuation_definition_tag_end_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;upto&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;column_index_max&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;column_index&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_begin punctuation_definition_tag_begin_html"&gt;&amp;lt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html"&gt;td&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_end punctuation_definition_tag_end_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
          &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%=&lt;/span&gt; row&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;select &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;cell&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; cell&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;column_index &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;==&lt;/span&gt; column_index &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;contents &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_begin punctuation_definition_tag_begin_html"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html"&gt;td&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_end punctuation_definition_tag_end_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_begin punctuation_definition_tag_begin_html"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html"&gt;tr&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_end punctuation_definition_tag_end_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_tag meta_tag_inline meta_tag_inline_any meta_tag_inline_any_html"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_begin punctuation_definition_tag_begin_html"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_inline entity_name_tag_inline_any entity_name_tag_inline_any_html"&gt;table&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_end punctuation_definition_tag_end_html"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Given the import cells collected by the CSV controller together with the index maxima, this view code builds a standard HTML table comprised of &lt;code&gt;tr&lt;/code&gt; and &lt;code&gt;td&lt;/code&gt; (table row and table data) tags. The &lt;code&gt;row =&lt;/code&gt; line (line 3) optimises the iteration somewhat by first collecting together all cells matching the current row index. This is a smaller number of cells from which to select individual cells matching the column index within the inner loop.&lt;/p&gt;

&lt;h2&gt;Merging, stage 2&lt;/h2&gt;

&lt;p&gt;At this point, you can navigate to &lt;a href="http://localhost:3000/csv/import"&gt;http://localhost:3000/csv/import&lt;/a&gt;. You can generate and drop a CSV file from Finder onto the Choose File button (a Mac shortcut for choosing a file) and click Upload. The Rails application then uploads and builds an import table of cells. By redirection, the app then displays the table. So far so good.&lt;/p&gt;

&lt;p&gt;However, this is only half the story. What the user actually wants to do is to create People and Places. The CSV information is just the raw data. Some of the columns will contain names of people (first name, last name) while some columns may contain addresses. The columns just contain random words of course, unless you have some real data to play with. But you get the idea. The data needs &lt;em&gt;merging&lt;/em&gt; with the other tables to create workable records.&lt;/p&gt;

&lt;p&gt;Sketch below outlines the design for merging CSV import tables.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://images.pioneeringsoftware.co.uk/Pick-a-table-to-merge-into.png" title="Sketch" alt="Sketch" /&gt;&lt;/p&gt;

&lt;p&gt;We will add a row of table headers to the import table viewing page. Initially they will contain empty &amp;#8216;select&amp;#8217; buttons. The user starts by selecting which table to import into. After choosing, the page will automatically update the column headers with the appropriate choices for input field mapping. If the chosen table is Person, column choices switch to none, first name or last name. For Places, only two choices: none or address. The user can then assign columns to fields, clicking Merge when ready.&lt;/p&gt;

&lt;p&gt;We therefore want the import-table show page to become dynamic. When the user selects the table, the selectors for column field must change appropriately. To make this happen, we take a page out of &lt;a href="http://railscasts.com/episodes/88-dynamic-select-menus"&gt;Ryan Bates&amp;#8217; book&lt;/a&gt;. Since the database records are static, we can set up a JavaScript array of mappings between tables and columns. When the user selects the table to import into, person or place, JavaScript within the page can respond by updating the column selectors.&lt;/p&gt;

&lt;h3&gt;Converting to jQuery with UJS&lt;/h3&gt;

&lt;p&gt;We plan to use jQuery rather than Prototype as our JavaScript framework. By default however, Rails has set up our application to include &lt;a href="http://www.prototypejs.org/"&gt;Prototype&lt;/a&gt; and &lt;a href="http://script.aculo.us/"&gt;script.aculo.us&lt;/a&gt;. Remove the following list of files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;public/javascripts/controls.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public/javascripts/dragdrop.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public/javascripts/effects.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;public/javascripts/prototype.js&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Replace the &lt;code&gt;rails.js&lt;/code&gt; &lt;a href="http://www.railsinside.com/tips/451-howto-unobtrusive-javascript-with-rails-3.html"&gt;UJS&lt;/a&gt; script found in &lt;code&gt;public/javascripts&lt;/code&gt; with the jQuery-based version found at &lt;a href="http://github.com/rails/jquery-ujs/raw/master/src/rails.js"&gt;GitHub&lt;/a&gt;. UJS stands for Unobtrusive JavaScript, new in Rails 3. By making use of &lt;a href="http://html5demos.com/"&gt;HTML 5 enhancements&lt;/a&gt;, the UJS feature avoids littering HTML pages with embedded JavaScript. Download and install &lt;a href="http://code.jquery.com/jquery-1.4.1.min.js"&gt;jQuery 1.4.1&lt;/a&gt; in the same place, at &lt;code&gt;public/javascripts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There is one more thing to do before jQuery becomes the new default JavaScript framework for our application: create a new &amp;#8216;initialiser&amp;#8217; to override Prototype and script.aculo.us as the default framework. Create a new Ruby script, &lt;code&gt;config/initializers/jquery.rb&lt;/code&gt;; exact name is not critical. This will run when the Rails server initialises. Add the following code.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_helper"&gt;&lt;span class="meta meta_module meta_module_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_module keyword_control_module_ruby"&gt;module&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_module entity_name_type_module_ruby"&gt;&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_module entity_other_inherited-class_module_first entity_other_inherited-class_module_first_ruby"&gt;ActionView&lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_module entity_other_inherited-class_module_second entity_other_inherited-class_module_second_ruby"&gt;Helpers&lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;::&lt;/span&gt;&lt;/span&gt;AssetTagHelper&lt;/span&gt;&lt;/span&gt;
  remove_const &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;JAVASCRIPT_DEFAULT_SOURCES&lt;/span&gt;
  &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;JAVASCRIPT_DEFAULT_SOURCES&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_literal string_quoted_other_literal_lower string_quoted_other_literal_lower_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%w(&lt;/span&gt;jquery-1.4.1.min rails&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;
  reset_javascript_include_default
&lt;/span&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This will override the default JavaScript sources with jQuery 1.4.1 and its UJS helper. jQuery ready!&lt;/p&gt;

&lt;h3&gt;Table headers, table selection, Merge button&lt;/h3&gt;

&lt;p&gt;Next, we need to add the import table headers, a table selection and a Merge button to the current import-table viewing code. Add the following. I&amp;#8217;ve commented out where the table contents go, just to make it a little clearer.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails source_ruby_rails_rjs"&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&amp;lt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;%&lt;/span&gt; form_for &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;merge&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;f&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;-&lt;/span&gt;&lt;span class="string string_quoted string_quoted_other string_quoted_other_literal string_quoted_other_literal_other string_quoted_other_literal_other_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%&amp;gt;&lt;/span&gt;
  &amp;lt;table border="1" cellspacing="1" cellpadding="1"&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&amp;lt;&lt;/span&gt;tr&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&amp;lt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;%&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;upto&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;column_index_max&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;column_index&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_literal string_quoted_other_literal_other string_quoted_other_literal_other_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%&amp;gt;&lt;/span&gt;
        &amp;lt;th&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
          &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&amp;lt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;%=&lt;/span&gt; f&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;select&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;column_index&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_literal string_quoted_other_literal_other string_quoted_other_literal_other_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%&amp;gt;&lt;/span&gt;
        &amp;lt;/th&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&amp;lt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;%&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_literal string_quoted_other_literal_other string_quoted_other_literal_other_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%&amp;gt;&lt;/span&gt;
    &amp;lt;/tr&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; same as before goes here
&lt;/span&gt;  &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&amp;lt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;/&lt;/span&gt;table&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&amp;lt;&lt;/span&gt;label&amp;gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&amp;lt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;%=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;Select a table for merging:&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_literal string_quoted_other_literal_other string_quoted_other_literal_other_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%&amp;gt;&lt;/span&gt;&amp;lt;/label&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&amp;lt;&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;%=&lt;/span&gt; f&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;select&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;table&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;tables&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;collect &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;t&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;t&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; t&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;include_blank&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;true&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;onchange&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;mergeTableSelected();&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_literal string_quoted_other_literal_other string_quoted_other_literal_other_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%&amp;gt;&lt;/span&gt;
  &amp;lt;%= f.submit "Merge", :disable_with =&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;Merging...&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_literal string_quoted_other_literal_other string_quoted_other_literal_other_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%&amp;gt;&lt;/span&gt;
&amp;lt;% end -%&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Some things to note about this code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It encloses the entire table within a form. That means that the form will send a POST request with the form parameters as fields. Within the receiving controller method, expression &lt;code&gt;params[:merge]&lt;/code&gt; will answer a Hash of values: one for each of the columns, and one for the selected table.&lt;/li&gt;
&lt;li&gt;Initially, the table headers are null selections. It will produce select tags with no options. We will fill this with content using JavaScript when the user chooses which table (people or places) for merging into.&lt;/li&gt;
&lt;li&gt;Whenever the user changes the table selection, the browser will invoke a JavaScript function named &lt;code&gt;mergeTableSelected&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The code accesses an instance variable &lt;code&gt;@tables&lt;/code&gt;. This is not yet defined. But we will now define it in the import tables controller as follows.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_controller"&gt;&lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;tables&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Base&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;connection&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;tables&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;select &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;t&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; t &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;!=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;schema_migrations&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This code performs a little bit of Active Record introspection. It asks Rails for the tables associated with its database connection. The answer is an array of table names, strings. The Array select method de-selects the &lt;code&gt;schema_migrations&lt;/code&gt; table, an internal table used by Rails. We want our app to ignore this one, in future possibly others too.&lt;/p&gt;

&lt;h3&gt;Merge table selected&lt;/h3&gt;

&lt;p&gt;Next, add the following JavaScript code to the &lt;code&gt;show.html.erb&lt;/code&gt; amoung the import tables views. It injects a blob of JavaScript into the show page.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="text text_html text_html_ruby"&gt;&lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%=&lt;/span&gt; javascript_tag &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  var columns = new Array();
  &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;for&lt;/span&gt; table &lt;span class="keyword keyword_control keyword_control_ruby"&gt;in&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;tables&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;for&lt;/span&gt; column &lt;span class="keyword keyword_control keyword_control_ruby"&gt;in&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Base&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;const_get&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Base&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;class_name&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;table&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;))&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;columns &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;
      columns.push(new Array('&lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%=&lt;/span&gt; table &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;', '&lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%=&lt;/span&gt; column&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;name &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;'));
    &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  function mergeTableSelected() {
    var o = $('select#merge_table option:selected');
    $('th select option').remove();
    $('th select').each(function(i, select) {
      select.options.add(new Option());
      $.each(columns, function(j, column) {
        if (o.text() == column[0]) {
          select.options.add(new Option(column[1]));
        }
      });
    });
  }
&lt;span class="source source_ruby source_ruby_rails source_ruby_rails_embedded source_ruby_rails_embedded_html"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;When Rails renders the page, it iterates the introspected &lt;code&gt;@tables&lt;/code&gt;, building an array of arrays called &lt;code&gt;columns&lt;/code&gt;. Each element contains a table name and a column name. When the user picks a table, the &lt;code&gt;mergeTableSelected()&lt;/code&gt; function accesses the selection, removes all existing options from the table header select tags and fills them with new options based on the column names matching the newly selected table name. Does that make sense? The JavaScript relies on jQuery of course. See &lt;a href="http://docs.jquery.com/"&gt;jQuery documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;The merge&lt;/h3&gt;

&lt;p&gt;Finally, the actual merge operation. When the user clicks Merge, their browser posts the parameters to &lt;code&gt;import_tables/:id&lt;/code&gt; where &lt;code&gt;:id&lt;/code&gt; stands for the unique identifier of the relevant import table. We need to match this to a method on the import tables controller. Add the following route to &lt;code&gt;routes.rb&lt;/code&gt;.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;  match &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;import_tables/:id&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;import_tables#merge&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And add the &lt;code&gt;merge&lt;/code&gt; method implementation.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_controller"&gt;  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;merge&lt;/span&gt;&lt;/span&gt;
&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; Uncomment the following line if you want to debug this method. However,
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; do not forget to uncomment the gem 'ruby-debug' in Gemfile also; this
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; assumes you have the ruby-debug gem installed too, and do the usual
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; thing if not, i.e. sudo gem install ruby-debug. Calling "debugger"
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; inserts a break point when the server hits this point in the
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; application. From that point you can interrogate the Rails state, single
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; step over or into message-sends and so forth. Very useful for debugging!
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; debugger
&lt;/span&gt;    
    import_table &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;ImportTable&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;find&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;params&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    import_cells &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; import_table&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;import_cells
    row_index_max &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; import_cells&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;map &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;cell&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; cell&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;row_index &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;max
    column_index_max &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; import_cells&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;map &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;cell&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; cell&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;column_index &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;max
    
&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; Pull the merge parameters from the POST request. The form sets up the
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; column mappings and merge table choice. Then use a little bit of
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; ActiveRecord introspection to derive the table's class name followed by
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; the class object. We will use this latter object to instantiate the
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; merged records.
&lt;/span&gt;    merge &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; params&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;merge&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;
    merge_table &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; merge&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;table&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;
    klass &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Base&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;const_get&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Base&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;class_name&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;merge_table&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;))&lt;/span&gt;
    
&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; Determine which columns have been mapped. Ignore the rest. Intersect the
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; requested column names with actual column names. Perhaps we should abort
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; and display some error message if the intersection proves empty because
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; the user did not select any columns.
&lt;/span&gt;    inverted_merge &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; merge&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;invert
    column_names &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; inverted_merge&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;keys &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;&amp;amp;&lt;/span&gt; klass&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;column_names
    
&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; Finally, create new instances, one per row. Iterate the rows, then for
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; each row, iterate the mapped columns. Select the matching cell and
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; update the record's corresponding column. Redirect to the merged table
&lt;/span&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; when done.
&lt;/span&gt;    &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;upto&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;row_index_max&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;row_index&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
      row &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; import_cells&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;select &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;cell&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; cell&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;row_index &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;==&lt;/span&gt; row_index &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;
      instance &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; klass&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;
      column_names&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;column_name&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
        column_index &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; inverted_merge&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;column_name&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_i
        contents &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; row&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;select &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;cell&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; cell&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;column_index &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;==&lt;/span&gt; column_index &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;contents
        instance&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;column_name&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; contents
      &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
      instance&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;save
    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
    eval &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;redirect_to &lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;merge_table&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;_path&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Hopefully, the in-line comments will help to elucidate what this method is doing and why.&lt;/p&gt;

&lt;h1&gt;Conclusions&lt;/h1&gt;

&lt;p&gt;What have we learned? Importing CSV is relatively straightforward using Rails 3 and jQuery. But the exercise has raised some outstanding questions and pointed forward to some interesting future directions.&lt;/p&gt;

&lt;h2&gt;Outstanding questions&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Uploading of CSV files does not deal with encoding issues. For the English language that might not be an enormous problem. But supporting other languages might begin to throw up bigger and bigger issues depending on how exotic the language needing conversion to Unicode (the internal encoding). There may also be number-formatting issues, e.g. some languages use commas for full stops (periods) within numbers.&lt;/li&gt;
&lt;li&gt;Column typing has not been considered. Some CSV columns may contain strings, others numbers. How these convert from CSV to real data within the application will depend on the conversion path between uploading and merging of data.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Future directions&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Some CSV files may have headings in the first row. Import merging might be friendlier if the user could ignore the first row by checking a box entitled, &amp;#8220;Ignore first row.&amp;#8221;&lt;/li&gt;
&lt;li&gt;The software does not yet support any form of row selection and de-selection. It merges &lt;em&gt;all&lt;/em&gt; rows. A real application would need to trim off the fat: remove duplicates, sort by columns, combine rows by dragging and dropping cell contents in-between rows, etc.&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/h7CCwxdLQDw" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 13 Jul 2010 07:52:29 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:e7ede900-974e-4203-a0b0-f153463cc5d2</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2010/07/13/import-csv-files-in-rails-3#comments</comments>
      <category>Rails</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=25</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/h7CCwxdLQDw/import-csv-files-in-rails-3</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2010/07/13/import-csv-files-in-rails-3</feedburner:origLink></item>
    <item>
      <title>Retaining C++ Objects</title>
      <description>&lt;p&gt;C++ and Objective-C do not always mix too well, although the two languages are fully compatible.&lt;/p&gt;

&lt;p&gt;With respect to compilation phases, alternating between C, C++, Objective-C and Objective-C++ presents no problem. You just write your software accordingly, freely mixing C, Objective-C, C++ and Objective-C++. Just make sure that the compiler knows what each translation unit contains, normally by source file extension: &lt;code&gt;c&lt;/code&gt; for C; &lt;code&gt;cc&lt;/code&gt; or &lt;code&gt;cpp&lt;/code&gt; or &lt;code&gt;cxx&lt;/code&gt; for C++; &lt;code&gt;m&lt;/code&gt; for Objective-C; and &lt;code&gt;mm&lt;/code&gt; for Objective-C++.&lt;/p&gt;

&lt;p&gt;That being specified correctly, your sources compile and link without issues. Only when you start running the code side-by-side however, you might find that memory management can become something of a mishmash. Basic C++ fundamentally has no memory management; I mean nothing automatic. Asking for memory when you want it, freeing memory when you&amp;#8217;re done with it: that is all bare C++ gives you. So you typically just roll your own, or find some more-advanced alternative such as &lt;a href="http://www.hpl.hp.com/personal/Hans_Boehm/gc/"&gt;Boehm&amp;#8217;s garbage collector&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Wouldn&amp;#8217;t it be nice however, if you could just simply &lt;em&gt;retain&lt;/em&gt;, &lt;em&gt;release&lt;/em&gt; and &lt;em&gt;auto-release&lt;/em&gt; your C++ objects, just like you do with &lt;code&gt;NSObject&lt;/code&gt;s? It would be very nice.&lt;/p&gt;

&lt;p&gt;This article outlines a little &amp;#8220;trick&amp;#8221; for retaining C++ objects on Mac and iPhone. It takes advantage of C++ inheritance; and is simple, so no dependence on internals of &lt;code&gt;CFTypeRef&lt;/code&gt; or &lt;code&gt;NSObject&lt;/code&gt;. The memory cost is low; just one additional &lt;code&gt;NSObject&lt;/code&gt;-derived object per retained C++ object. Final feature, implementation separates from interface by design. Hence you can include retaining within bodies of source &lt;em&gt;without&lt;/em&gt; the things being retained having any knowledge of Objective-C. Translation units remain plain old C++, no additional dependencies. The implementation exists apart.&lt;/p&gt;

&lt;p&gt;MIT-licensed code provided in full.&lt;/p&gt;

&lt;h2&gt;Who Cares?&lt;/h2&gt;

&lt;p&gt;The audience for this topic are developers wanting to integrate C++ libraries with Objective-C on iPhone or Mac under the retain-release management paradigm. C++ objects become subject to standard Apple memory management, even without classes being aware of it.&lt;/p&gt;

&lt;h2&gt;Start With a Test&lt;/h2&gt;

&lt;p&gt;Always best: start with a test.&lt;/p&gt;

&lt;h3&gt;Basic failing test&lt;/h3&gt;

&lt;p&gt;Allocate a C++ object. Then autorelease it. Place this within an autorelease pool context. Initially test-failing gives a leak. Test-success eliminates the leak. This is the test.&lt;/p&gt;

&lt;p&gt;In code form, it looks like this.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Instantiate an instance of TestClass. Retain then auto-release it. Within
// the context of an auto-release pool, will it delete?
pool = [[NSAutoreleasePool alloc] init];
(new TestClass)-&amp;gt;retain().autorelease();
[pool release];
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;TestClass&lt;/code&gt; has the following basic definition.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class TestClass : public c_plus_plus_retained
{
public:
    TestClass()
    {
        log("hello");
    }
    ~TestClass()
    {
        log("goodbye");
    }
private:
    void log(const char *message)
    {
        // print message
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;While &lt;code&gt;c_plus_plus_retained&lt;/code&gt; has the following declaration.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;struct c_plus_plus_retained
{
    // constructors &amp;amp; virtual destructor
    c_plus_plus_retained() : retainer_object(0) {}
    c_plus_plus_retained(const c_plus_plus_retained &amp;amp;copy) : retainer_object(0) {}
    virtual ~c_plus_plus_retained() {}

    // mirroring NSObject semantics
    c_plus_plus_retained &amp;amp;retain();
    void release();
    c_plus_plus_retained &amp;amp;autorelease();

    // accessor
    void *retainer();

private:
    void *retainer_object;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The above code declares a pure C++ public interface; notice there are no includes hence no other dependencies. Any general C++ translation unit can see this interface declaration without baulking. It contains nothing about Objective-C or Objective-C++. Such dependencies appear at link- and run-time, not at compile-time.&lt;/p&gt;

&lt;p&gt;This is by design. You can include this header in any C++ source.&lt;/p&gt;

&lt;h2&gt;Successful Implementation&lt;/h2&gt;

&lt;p&gt;The implementation allocates an &lt;code&gt;NSObject&lt;/code&gt;-derived retainer which deletes the retained C++ instance during its &lt;code&gt;-dealloc&lt;/code&gt; method.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_c++"&gt;c_plus_plus_retained &amp;amp;&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;c_plus_plus_retained::retain&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;()&lt;/span&gt;
&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;retainer_object)
    &lt;span class="meta meta_block meta_block_c"&gt;{
        [(CPlusPlusRetainer *)retainer_object retain];
    }&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;else&lt;/span&gt;
    &lt;span class="meta meta_block meta_block_c"&gt;{
        retainer_object = [[CPlusPlusRetainer alloc] initWithRetained:&lt;span class="variable variable_language variable_language_c++"&gt;this&lt;/span&gt;];
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Hereafter you must never delete this object. Doing so will break the
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; implicit design contract. Asking to retain actually places the
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; retained object within the scope of retain-release memory
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; management. Only releasing hereafter will release the retainer and
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; delete the object. Henceforward, delete becomes release. Calling
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; delete will double-delete this object.
&lt;/span&gt;    }&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; *&lt;span class="variable variable_language variable_language_c++"&gt;this&lt;/span&gt;;
}&lt;/span&gt;&lt;/span&gt;

&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;c_plus_plus_retained::release&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;()&lt;/span&gt;
&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;retainer_object)
    &lt;span class="meta meta_block meta_block_c"&gt;{
        [(CPlusPlusRetainer *)retainer_object release];
    }&lt;/span&gt;
}&lt;/span&gt;&lt;/span&gt;

c_plus_plus_retained &amp;amp;&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;c_plus_plus_retained::autorelease&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;()&lt;/span&gt;
&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;retainer_object)
    &lt;span class="meta meta_block meta_block_c"&gt;{
        [(CPlusPlusRetainer *)retainer_object autorelease];
    }&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; *&lt;span class="variable variable_language variable_language_c++"&gt;this&lt;/span&gt;;
}&lt;/span&gt;&lt;/span&gt;

&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt; *&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;c_plus_plus_retained::retainer&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;()&lt;/span&gt;
&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;retainer_object == &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;)
    &lt;span class="meta meta_block meta_block_c"&gt;{
&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"&gt;        &lt;/span&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;retain&lt;/span&gt;(&lt;/span&gt;).&lt;span class="meta meta_function-call meta_function-call_c"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_c"&gt;autorelease&lt;/span&gt;(&lt;/span&gt;);
    }&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; retainer_object;
}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Semantically, the &lt;code&gt;c_plus_plus_retained&lt;/code&gt; class initially has no retain count. It remains initially invisible respecting retain-release memory management. This changes when you retain it for the first time. At that point, you no longer &lt;code&gt;delete&lt;/code&gt; the object. You must release it, doing so manually or by auto-releasing.&lt;/p&gt;

&lt;h3&gt;Beware the C++ Copy Constructor!&lt;/h3&gt;

&lt;p&gt;By default the compiler supplies a bitwise copy that copies everything verbatim. If you create a copy however, the duplicate has no retainer. If you want duplicates to retain then invoke &lt;code&gt;retain()&lt;/code&gt;. If you want duplicates to auto-release invoke &lt;code&gt;retained-&amp;gt;retain().autorelease()&lt;/code&gt; assuming &amp;#8221;&lt;code&gt;retained&lt;/code&gt;&amp;#8221; is a pointer to &lt;code&gt;c_plus_plus_retained&lt;/code&gt; or its sub-class.&lt;/p&gt;

&lt;h1&gt;Grab a Copy&lt;/h1&gt;

&lt;p&gt;The repositories live on GitHub at &lt;a href="http://github.com/royratcliffe/CPlusPlus"&gt;Library of useful C++ classes for iPhone and Mac&lt;/a&gt; and &lt;a href="http://github.com/royratcliffe/CPlusPlusRetained"&gt;iPhone app project encapsulating tests for &lt;code&gt;c_plus_plus_retained&lt;/code&gt;&lt;/a&gt;. Drop the iPhone app project into the Library folder then open, build and run. You&amp;#8217;ll see something like this (memory addresses will vary, of course).&lt;/p&gt;

&lt;p&gt;&lt;img src="http://pioneeringsoftware.s3.amazonaws.com/blog/Screen%20shot%202010-03-12%20at%2010.51.33.png" alt="Screenshot" /&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/nezm_drrE0c" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 09 Mar 2010 22:31:53 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:1769ec23-7edf-41da-850b-41e6cee9c225</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2010/03/09/retaining-c-objects#comments</comments>
      <category>Foundation</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=19</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/nezm_drrE0c/retaining-c-objects</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2010/03/09/retaining-c-objects</feedburner:origLink></item>
    <item>
      <title>Gloss Caustic Shader for iPhone</title>
      <description>&lt;p&gt;&lt;a href="http://oleb.net/"&gt;Ole Begemann&lt;/a&gt; has done some very useful work, porting the &lt;a href="http://blog.pioneeringsoftware.co.uk/2008/12/09/gloss-caustic-shading"&gt;gloss-caustic shader&lt;/a&gt; to iPhone OS. This work has been long overdue. Many thanks Ole!&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve merged Ole&amp;#8217;s changes into my &lt;a href="http://github.com/royratcliffe/gloss-caustic-shader"&gt;Git repo&lt;/a&gt;, albeit with a few modifications. This article outlines the changes to the changes.&lt;/p&gt;

&lt;h2&gt;What has changed?&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ll not dig too much into Ole&amp;#8217;s enhancements. Ole does that on his &lt;a href="http://oleb.net/blog/2010/02/porting-rrglosscausticshader-to-the-iphone/"&gt;page&lt;/a&gt;. In summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shader sources compile for OS X &lt;strong&gt;and&lt;/strong&gt; iPhone OS.&lt;/li&gt;
&lt;li&gt;Has two sample projects, one for OS X and the other for iPhone.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;img src="http://pioneeringsoftware.s3.amazonaws.com/blog/Screen%20shot%202010-03-05%20at%2005.17.07.png" alt="Gloss Caustic Shader on iPhone" /&gt;&lt;/p&gt;

&lt;h2&gt;Why does it need porting?&lt;/h2&gt;

&lt;p&gt;The fundamental difference between iPhone and OS X for the gloss-caustic shader concerns its use of &lt;a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSColor_Class/Reference/Reference.html"&gt;NSColor&lt;/a&gt;. Simply put, iPhone does &lt;strong&gt;not&lt;/strong&gt; have such a class; instead, it has &lt;a href="http://developer.apple.com/IPhone/library/documentation/UIKit/Reference/UIColor_Class/Reference/Reference.html"&gt;UIColor&lt;/a&gt; with limited support for colour spaces and no support for RGB-to-HSB conversion.&lt;/p&gt;

&lt;p&gt;Strangely, you &lt;em&gt;can&lt;/em&gt; make the reverse conversion, from HSB to RGB by invoking class method&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+colorWithHue:saturation:brightness:alpha: 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and UIKit answers with a colour with triple RGB components whence you can access the red, green, blue and alpha component values. But iPhone has no instance method&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;-getHue:saturation:brightness:alpha: 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;as does OS X.&lt;/p&gt;

&lt;h1&gt;The basic approach&lt;/h1&gt;

&lt;p&gt;The simple approach Ole takes is to surround the difference between OS X and iPhone with &lt;code&gt;#if TARGET_OS_IPHONE&lt;/code&gt;, &lt;code&gt;#else&lt;/code&gt;, &lt;code&gt;#endif&lt;/code&gt; blocks. Xcode defines &lt;code&gt;TARGET_OS_IPHONE&lt;/code&gt; only when compiling for iPhone.&lt;/p&gt;

&lt;p&gt;Under normal circumstances, I would avoid this approach since it makes code difficult to read and maintenance harder in the long run. Nevertheless, the pre-processor conditional blocks turns out relatively small in number and in extent. Each one in general surrounds just one line of code: the first condition presents the iPhone&amp;#8217;s &lt;a href="http://developer.apple.com/IPhone/library/documentation/UIKit/Reference/UIColor_Class/Reference/Reference.html"&gt;UIColor&lt;/a&gt;-based alternative, while the second condition presents OS X&amp;#8217;s &lt;a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSColor_Class/Reference/Reference.html"&gt;NSColor&lt;/a&gt;-based alternative.&lt;/p&gt;

&lt;h2&gt;Maintaining semantics&lt;/h2&gt;

&lt;p&gt;Ole has included a number of useful functions for colour conversion, based on work by &lt;a href="http://arstechnica.com/apple/guides/2009/02/iphone-development-accessing-uicolor-components.ars"&gt;Erica Sadun&lt;/a&gt; and some standard RGB-to-HSB conversion code. I&amp;#8217;ve repackaged these as extensions on &lt;a href="http://developer.apple.com/IPhone/library/documentation/UIKit/Reference/UIColor_Class/Reference/Reference.html"&gt;UIColor&lt;/a&gt; with semantics mirroring that of &lt;a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSColor_Class/Reference/Reference.html"&gt;NSColor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Interface for &lt;code&gt;UIColor(RRUIKit)&lt;/code&gt; as follows.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Fill in some of the "missing" UIColor methods, making UIColor more compatible
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; with NSColor. This includes access to individual colour components and HSV
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; conversion. Use similar method signatures and semantics as far as possible.
&lt;/span&gt;
&lt;span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;interface&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;UIColor&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"&gt;(RRUIKit)

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;UIColor *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;colorUsingColorSpaceModel&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;CGColorSpaceModel&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;model&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;CGColorSpaceRef&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;colorSpace&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;CGColorSpaceModel&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;colorSpaceModel&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_cocoa support_type_cocoa_leopard"&gt;NSUInteger&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;numberOfComponents&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;getComponents&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;components&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;redComponent&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;greenComponent&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;blueComponent&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;alphaComponent&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;

&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;---------------------------------------------------- Hue-Saturation-Brightness
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;getHue&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;hue&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;saturation&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;saturation&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;brightness&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;brightness&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;alpha&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;alpha&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Answers the components of RGB colours as hue, saturation and
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; brightness. Adds the missing UIColor method for converting RGB to
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; HSB. This method assumes that self (an instance of UIColor) has RGB
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; colour model.
&lt;/span&gt;
&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Serialisation&lt;/h2&gt;

&lt;p&gt;Ole implements a set of extensions on &lt;code&gt;RRGlossCausticShader&lt;/code&gt; for saving shader setting to a dictionary. I&amp;#8217;ve enhanced this functionality by implementing the &lt;code&gt;NSCoding&lt;/code&gt; protocol for shader and matcher classes.&lt;/p&gt;

&lt;p&gt;Coding adds a level of extra flexibility. The coding protocol lets you serialise trees of objects (the shader and its enclosed matcher) by archiving to &lt;em&gt;any&lt;/em&gt; data stream.&lt;/p&gt;

&lt;h2&gt;Key-value coding&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ve also simplified the iPhone sample&amp;#8217;s view controller. iPhone OS does not include bindings. Hence implementing the update cycle within the controller can become rather tedious when there are many control elements, such as with gloss-caustic shaders.&lt;/p&gt;

&lt;p&gt;My enhancement on Ole&amp;#8217;s enhencement employs key-value coding, i.e. accessing properties via &lt;code&gt;-valueForKeyPath:&lt;/code&gt; and &lt;code&gt;-setValue:forKeyPath:&lt;/code&gt;. It makes things a little less long-winded.&lt;/p&gt;

&lt;h1&gt;Your feedback&lt;/h1&gt;

&lt;p&gt;As always, very welcome. Thanks again &lt;a href="http://oleb.net/"&gt;Ole&lt;/a&gt;. Your improvements are much appreciated. You can find Ole&amp;#8217;s work at &lt;a href="http://github.com/ole/gloss-caustic-shader"&gt;GitHub&lt;/a&gt;. Mine also at &lt;a href="http://github.com/royratcliffe/gloss-caustic-shader"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/xlOr3Lejp9w" height="1" width="1"/&gt;</description>
      <pubDate>Thu, 04 Mar 2010 20:47:00 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:9b521ba7-3551-45b5-9929-08b6316a4c82</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2010/03/04/gloss-caustic-shader-for-iphone#comments</comments>
      <category>AppKit</category>
      <category>UIKit</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=17</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/xlOr3Lejp9w/gloss-caustic-shader-for-iphone</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2010/03/04/gloss-caustic-shader-for-iphone</feedburner:origLink></item>
    <item>
      <title>Gloss-Caustic Shading</title>
      <description>&lt;p&gt;Matt Gallagher recently wrote a very useful article about &lt;a href="http://cocoawithlove.com/2008/09/drawing-gloss-gradients-in-coregraphics.html"&gt;drawing gloss gradients using Core Graphics&lt;/a&gt;. In his article, Matt describes how to reproduce the oft-seen glossy gradient effect. Thanks Matt! It&amp;#8217;s a nice article. &amp;#8220;Cocoa with Love&amp;#8221; lovingly provides the working source code. This little article aims to complement Matt&amp;#8217;s work.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve also re-factored the software and packaged the result within an Objective-C class called &lt;code&gt;RRGlossCausticShader&lt;/code&gt;. This packaging automatically adds support for key-value coding and observing. Bindings then let you easily wrap the class within a little application able to adjust the many parameters interactively.&lt;/p&gt;

&lt;h1&gt;Show me the money&lt;/h1&gt;

&lt;p&gt;Before going any further, you might first want to see the results. I know &lt;em&gt;I&lt;/em&gt; would! &lt;a href="http://pioneeringsoftware.s3.amazonaws.com/blog/GlossCausticShader.zip"&gt;Download&lt;/a&gt; the project to play with the shader. Compile and run the application using Xcode. The main window appears as follows. Inspector panels also appear from where you can interactively adjust the many shading parameters.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://pioneeringsoftware.s3.amazonaws.com/blog/2008-12-10_gloss_caustic_shader_window.png" alt="Gloss Caustic Shader Window" /&gt;&lt;/p&gt;

&lt;p&gt;Gloss above, caustic below. Those are the two halves of the shading. Gloss appears in the top half, caustic in the bottom half. Within each half, an exponential function blends a given non-caustic base colour with whiteness above and with &lt;em&gt;matching&lt;/em&gt; caustic colour below. The main window displays these basic elements of the shading process: the shading itself (left), non-caustic base colour (top right) and coefficient of the exponent function (bottom right).&lt;/p&gt;

&lt;h1&gt;Re-factoring&lt;/h1&gt;

&lt;p&gt;My version of Matt&amp;#8217;s work includes some re-factoring. Rather than just the one functional interface, the version that you&amp;#8217;ll find within the project involves three modular utility classes.
- &lt;code&gt;RRGlossCausticShader&lt;/code&gt; encapsulates shading
- &lt;code&gt;RRCausticColorMatcher&lt;/code&gt; finds caustic matches for given colours
- &lt;code&gt;RRExponentialFunction&lt;/code&gt; wraps the exponential maths
- &lt;code&gt;RRLuminanceFromRGBComponents&lt;/code&gt; returns luminance from RGB triples&lt;/p&gt;

&lt;p&gt;This re-factoring has some benefits. First, it promotes re-use. Other requirements may call for RGB-to-luminance conversion, or a generic exponential function for example; or you might want to sub-class the caustic colour matcher and add some customisation. Separating out the individual sub-requirements adds some extra scope for growth. I think it also makes the source code somewhat easier to follow and therefore comprehend. But that might just be my own personal opinion. Your mileage may vary, as they say!&lt;/p&gt;

&lt;p&gt;Anyway, the purpose of this article is to outline some of the differences in implementation and the underlying thinking. Comments welcome, of course.&lt;/p&gt;

&lt;h1&gt;Twinkle, twinkle&lt;/h1&gt;

&lt;p&gt;The gloss effect on the upper half of the gradient derives from the base colour&amp;#8217;s luminosity. So obtaining luminance from a given Red, Green and Blue is part of the glossing requirement.&lt;/p&gt;

&lt;p&gt;As you can see below, I replace Matt&amp;#8217;s conversion with the one described at &lt;a href="http://www.opengl.org/resources/code/samples/advanced/advanced97/notes/node140.html"&gt;OpenGL&lt;/a&gt;. The difference is small, almost non-existent. Only, the comment that &amp;#8220;Haeberli notes that [the YIQ colour conversion values used by Matt] are incorrect in a linear RGB colour space&amp;#8221; convinced me to make the small change. Just call me fussy.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;RRLuminanceFromRGBComponents&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(&lt;span class="storage storage_modifier storage_modifier_c"&gt;const&lt;/span&gt; &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; *rgb)&lt;/span&gt;
&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; 0.3086 + 0.6094 + 0.0820 = 1.0
&lt;/span&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_c"&gt;0.3086f&lt;/span&gt;*rgb&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; + &lt;span class="constant constant_numeric constant_numeric_c"&gt;0.6094f&lt;/span&gt;*rgb&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; + &lt;span class="constant constant_numeric constant_numeric_c"&gt;0.0820f&lt;/span&gt;*rgb&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;2&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Notice a few other things. I&amp;#8217;m using &lt;code&gt;CGFloat&lt;/code&gt; type for floats because this corresponds exactly with Apple&amp;#8217;s usage for colour components. Can we always assume that &lt;code&gt;CGFloat&lt;/code&gt; equals &lt;code&gt;float&lt;/code&gt;? No. In fact, &lt;code&gt;CGFloat&lt;/code&gt; is sometimes &lt;code&gt;double&lt;/code&gt;! This happens when 64-bit compiling for instance. Argument &lt;code&gt;const&lt;/code&gt;-correctness is another feature.&lt;/p&gt;

&lt;h1&gt;Caustic nature&lt;/h1&gt;

&lt;p&gt;The lower half of the gradient blends the base colour into shades of yellow (yellow is the default caustic hue). The lower end of the gradient starts to look more-and-more tinted towards the yellow. However, the precise colour depends upon the non-caustic base colour. For blue colours, for example, the default caustic switches to magenta. Blue looks better fading toward magenta, rather than yellow. In all cases though, the amount of caustic to non-caustic blending varies according to the cosine of the distance between the caustic and non-caustic hues.&lt;/p&gt;

&lt;p&gt;So rather than having a function handle the caustic colour matching and implementing the adjustable parameters as manifest constants, the new version implements a &amp;#8220;colour matching&amp;#8221; class. Interface listed below. The class implements adjustable parameters as read-write class properties with all the necessary setters and getters. This approach buys some advantages. It automatically adds support for key-value coding and observing. In practice, it means that user-interface controls can bind to these properties using Cocoa Bindings.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;interface&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;RRCausticColorMatcher&lt;/span&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_entity punctuation_definition_entity_other punctuation_definition_entity_other_inherited-class punctuation_definition_entity_other_inherited-class_objc"&gt;:&lt;/span&gt; &lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc"&gt;NSObject&lt;/span&gt;&lt;span class="meta meta_divider meta_divider_objc"&gt;
&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"&gt;&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; causticHue;
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Yellow by default.
&lt;/span&gt;    &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; graySaturationThreshold;
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Saturation level at which colours appear grey. Below this level,
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; matcher response snaps to pure caustic.
&lt;/span&gt;    &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; causticSaturationForGrays;
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Defines the caustic saturation for grey colours. Grey colours fall
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; below the grey saturation threshold. When saturation drops too low,
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; everything looks grey.
&lt;/span&gt;    &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; redHueThreshold;
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Colours at this threshold and above match to default caustics rather
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; than default magenta for blues.
&lt;/span&gt;    &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; blueHueThreshold;
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Triggers a switch to magenta caustics. Hues at blue and beyond
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; display magenta-modulated caustics by default.
&lt;/span&gt;    &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; blueCausticHue;
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Magenta by default. Magenta caustics for blue colours.
&lt;/span&gt;    &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; causticFractionDomainFactor;
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Expands or contracts the caustic fraction's domain. With factor equal
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; to 1, non-caustic and caustic hues blend according to the cosine of
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; their difference. Smaller the difference, greater the amount of
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; caustic hue. Defaults to 1.4 meaning that the point of absolutely no
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; caustic blending occurs at 1/1.4 difference from caustic hue. Try
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; plotting cos(x*pi*1.4) in the -1,1 interval.
&lt;/span&gt;    &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; causticFractionRangeFactor;
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Scales the caustic fraction which without a factor outputs a blending
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; fraction between 0 and 1 in favour of the caustic blend. Defaults to
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; 0.6 which scales down the amount of caustic hue-and-brightness by
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; that amount.
&lt;/span&gt;}&lt;/span&gt;

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSColor&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;matchForColor&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSColor&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;aColor&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Matches the given colour. Answers a matching caustic colour. The result
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; shifts hue and brightness towards yellow. Saturation remains unchanged.
&lt;/span&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;matchForHSB&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_modifier storage_modifier_c"&gt;const&lt;/span&gt; &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;hsb&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;caustic&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;outHSB&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Does the work.
&lt;/span&gt;
&lt;span class="meta meta_property-with-attributes meta_property-with-attributes_objc"&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc"&gt;@&lt;/span&gt;property&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;(&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_attribute"&gt;assign&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; causticHue;
&lt;span class="meta meta_property-with-attributes meta_property-with-attributes_objc"&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc"&gt;@&lt;/span&gt;property&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;(&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_attribute"&gt;assign&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; graySaturationThreshold;
&lt;span class="meta meta_property-with-attributes meta_property-with-attributes_objc"&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc"&gt;@&lt;/span&gt;property&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;(&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_attribute"&gt;assign&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; causticSaturationForGrays;
&lt;span class="meta meta_property-with-attributes meta_property-with-attributes_objc"&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc"&gt;@&lt;/span&gt;property&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;(&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_attribute"&gt;assign&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; redHueThreshold;
&lt;span class="meta meta_property-with-attributes meta_property-with-attributes_objc"&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc"&gt;@&lt;/span&gt;property&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;(&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_attribute"&gt;assign&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; blueHueThreshold;
&lt;span class="meta meta_property-with-attributes meta_property-with-attributes_objc"&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc"&gt;@&lt;/span&gt;property&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;(&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_attribute"&gt;assign&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; blueCausticHue;
&lt;span class="meta meta_property-with-attributes meta_property-with-attributes_objc"&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc"&gt;@&lt;/span&gt;property&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;(&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_attribute"&gt;assign&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; causticFractionDomainFactor;
&lt;span class="meta meta_property-with-attributes meta_property-with-attributes_objc"&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc"&gt;@&lt;/span&gt;property&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;(&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_attribute"&gt;assign&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt; causticFractionRangeFactor;

&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h1&gt;Exponentially&lt;/h1&gt;

&lt;p&gt;Shading employs an exponential function. As the gradient progresses from 0 to 0.5, gloss white blending increases &lt;em&gt;exponentially&lt;/em&gt; in the 0,1 interval. Progressing through the bottom half of the gradient from 0.5 to 1, caustic blending increases &lt;em&gt;exponentially&lt;/em&gt;. The implementation re-factors the &lt;a href="http://mathworld.wolfram.com/ExponentialFunction.html"&gt;exponential function&lt;/a&gt;. Interface listing below. It becomes a C-style object class and thereby minimises its dependencies: just plain C types and standard library &lt;code&gt;math.h&lt;/code&gt; and hence very suitable for repeated invocations from the &lt;em&gt;bowels&lt;/em&gt; of a shading function.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Encapsulates an optimising generic Exponential Function where
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;      y=1-(exp(x*-c)-exp(-c))/(1-exp(-c))
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; and where 0&amp;lt;c is a general coefficient describing the exponential
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; curvature. The function's input domain lies within the 0..1 interval, its
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; output range likewise. The implementation optimises by pre-computing those
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; constant terms depending only on the coefficient whenever the coefficient
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; changes. Repeated evaluation takes less computing time thereafter.
&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;struct&lt;/span&gt; RRExponentialFunction
&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="storage storage_type storage_type_c"&gt;float&lt;/span&gt; coefficient;
    &lt;span class="storage storage_type storage_type_c"&gt;float&lt;/span&gt; exponentOfMinusCoefficient;
    &lt;span class="storage storage_type storage_type_c"&gt;float&lt;/span&gt; oneOverOneMinusExponentOfMinusCoefficient;
}&lt;/span&gt;;

&lt;span class="storage storage_type storage_type_c"&gt;typedef&lt;/span&gt; &lt;span class="storage storage_type storage_type_c"&gt;struct&lt;/span&gt; RRExponentialFunction RRExponentialFunction;

&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;RRExponentialFunctionSetCoefficient&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(RRExponentialFunction *f, &lt;span class="storage storage_type storage_type_c"&gt;float&lt;/span&gt; c)&lt;/span&gt;;&lt;/span&gt;
&lt;span class="storage storage_type storage_type_c"&gt;float&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"&gt; &lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;RRExponentialFunctionEvaluate&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(RRExponentialFunction *f, &lt;span class="storage storage_type storage_type_c"&gt;float&lt;/span&gt; x)&lt;/span&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h1&gt;Shading&lt;/h1&gt;

&lt;p&gt;And finally, the &amp;#8220;gloss-caustic shader&amp;#8221; class brings all the disparate pieces together. The design aims for reusability. Idea is that you instantiate a shader, set up the parameters such as non-caustic colour or any other necessary adjustments to defaults, then re-use it over-and-over whenever you need to draw the shading.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;interface&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;RRGlossCausticShader&lt;/span&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_entity punctuation_definition_entity_other punctuation_definition_entity_other_inherited-class punctuation_definition_entity_other_inherited-class_objc"&gt;:&lt;/span&gt; &lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc"&gt;NSObject&lt;/span&gt;&lt;span class="meta meta_divider meta_divider_objc"&gt;
&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"&gt;&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="storage storage_type storage_type_c"&gt;struct&lt;/span&gt; RRGlossCausticShaderInfo *info;
    RRCausticColorMatcher *matcher;
}&lt;/span&gt;

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;drawShadingFromPoint&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_cocoa"&gt;NSPoint&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;startingPoint&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;toPoint&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_cocoa"&gt;NSPoint&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;endingPoint&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;inContext&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;CGContextRef&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;aContext&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;update&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Send -update after changing one or more parameters. Setters do not
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; automatically update the shader. This is by design. It applies to the
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; caustic colour matcher too. Change anything? Send an update. Otherwise,
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; if the setters automatically update, multiple changes trigger unnecessary
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; multiple updates. It's a small optimisation.
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Updating follows the dependency chain. Caustic colour depends on
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; non-caustic colour along with all the caustic colour matcher's tuneable
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; configuration settings. Updating also re-computes the gloss. Gloss
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; derives from non-caustic colour luminance, among other things.
&lt;/span&gt;
&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;---------------------------------------------------------------------- setters
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;setExponentialCoefficient&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;float&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;c&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;setNoncausticColor&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSColor&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;aColor&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Converts aColor to device RGB colour space. The resulting colour
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; components become the new non-caustic colour. This setter, like all
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; others, does not automatically readjust the dependencies. Invoke -update
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; after adjusting one or more settings.
&lt;/span&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;setGlossReflectionPower&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;powerLevel&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Assigns a new power level to the gloss reflection.
&lt;/span&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;setGlossStartingWhite&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;whiteLevel&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; White levels range between 0 and 1 inclusive. Gloss starting white levels
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; typically have higher values compared to ending white level.
&lt;/span&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;setGlossEndingWhite&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;whiteLevel&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;

&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;---------------------------------------------------------------------- getters
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;float&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;exponentialCoefficient&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSColor&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;noncausticColor&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Returns the non-caustic colour.
&lt;/span&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;glossReflectionPower&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;glossStartingWhite&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_type support_type_quartz"&gt;CGFloat&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;glossEndingWhite&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;

&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Key-value coding automatically gives access to colour matching for caustic
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; colours. Special note though, changing caustic matcher thresholds does not
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; (repeat not) automatically adjust the shader's caustic colour. You need to
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; update the shader when ready.
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Currently, the matcher property offers read-only access. You cannot set the
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; matcher! However, perhaps future versions will allow setting in order to
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; override the default caustic matching behaviour. Developers might want to
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; customise the colour matching algorithmically as well as by tweaking
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; parameters.
&lt;/span&gt;&lt;span class="meta meta_property-with-attributes meta_property-with-attributes_objc"&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc"&gt;@&lt;/span&gt;property&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;(&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_attribute"&gt;readonly&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;)&lt;/span&gt;&lt;/span&gt; RRCausticColorMatcher *matcher;

&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The &lt;a href="http://pioneeringsoftware.s3.amazonaws.com/blog/GlossCausticShader.zip"&gt;sample project&lt;/a&gt; explains how to use the shader. I hope it&amp;#8217;s clear enough. The sources have an MIT license. I haven&amp;#8217;t tried it out on iPhone or pre-Leopard Mac, so can&amp;#8217;t make any comments about portability except to say that porting &lt;em&gt;should&lt;/em&gt; be fairly straightforward. But no doubt you&amp;#8217;ve heard that before!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/OB0QPJ0fec4" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 09 Dec 2008 19:25:45 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:490e8910-8601-452c-939d-54252a354a2b</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2008/12/09/gloss-caustic-shading#comments</comments>
      <category>AppKit</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=14</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/OB0QPJ0fec4/gloss-caustic-shading</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2008/12/09/gloss-caustic-shading</feedburner:origLink></item>
    <item>
      <title>Outline view, tree controller and itemForPersistentObject</title>
      <description>&lt;p&gt;This is the scenario: your user interface comprises an outline view and a hierarchical data model. You want the outline view to display the hierarchy &lt;em&gt;and&lt;/em&gt; remember the expansion state automatically in preferences. Hence when the user re-runs the application, the items that were expanded are still expanded, and vice versa: what was collapsed remains so. Outline view, tree controller, hierarchical model, bindings. That&amp;#8217;s the recipe.&lt;/p&gt;

&lt;p&gt;According to some, storing expansion state of an outline view when used with a tree controller is not just difficult: it&amp;#8217;s &lt;a href="http://www.cocoadev.com/index.pl?OutlineViewCoreDataBindings"&gt;impossible&lt;/a&gt;! But is it? No, is the simple answer. It&amp;#8217;s actually quite easy. In this article I introduce a new helper class called &lt;code&gt;RROutlineViewExpandedItemsAutosaver&lt;/code&gt;! Original aren&amp;#8217;t I? It does not involve sub-classing or access to private methods. The solution presented uses only documented interfaces and only requires a small stateless class instance for handling all outline view auto-saving technicalities. It does assume Core Data use for modelling. But you can easily adapt the technique for other data-model implementations.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s impossible?&lt;/p&gt;

&lt;p&gt;At first it seems so. For a start, if you read the documentation for &lt;code&gt;setAutosaveExpandedItems:&lt;/code&gt; you can see that you also need to implement two data-source methods: &lt;code&gt;outlineView:itemForPersistentObject:&lt;/code&gt; and &lt;code&gt;outlineView:persistentObjectForItem:&lt;/code&gt;. Goes without saying, you also need a data source implementing those methods. Otherwise it does not work. In fact, it&amp;#8217;s not exactly clear what these two necessary methods are supposed to do. The document talks about translating to and from an &amp;#8220;archived object.&amp;#8221; What does that mean exactly?&lt;/p&gt;

&lt;p&gt;You can find a number of posts at CocoaBuilder on this issue. &lt;a href="http://www.cocoabuilder.com/archive/message/cocoa/2005/5/7/135189" title="NSOutlineView, NSTreeController and itemForPersistentObject"&gt;Keith Blount&lt;/a&gt; started a thread in 2005; &lt;a href="http://www.cocoabuilder.com/archive/message/cocoa/2006/4/17/161214" title="NSOutlineView setAutosaveExpandedItems"&gt;Nick Briggs&lt;/a&gt; asked about it again in 2006. But no answers forthcoming! Some discussion exists and some solutions have been posted at CocoaDev (&lt;a href="http://www.cocoadev.com/index.pl?OutlineViewCoreDataBindings"&gt;OutlineViewCoreDataBindings&lt;/a&gt; and &lt;a href="http://www.cocoadev.com/index.pl?NSOutlineViewStateSavingWithNSTreeController"&gt;NSOutlineViewStateSavingWithNSTreeController&lt;/a&gt;). But there is nothing definitive. Plus, the solution supplied relies on private methods and sub-classing. Messy!&lt;/p&gt;

&lt;h1&gt;Start with a test&lt;/h1&gt;

&lt;p&gt;In the spirit of &lt;a href="http://en.wikipedia.org/wiki/Agile_software_development"&gt;Agile&lt;/a&gt;, let&amp;#8217;s start with a test that fails.&lt;/p&gt;

&lt;p&gt;Apple&amp;#8217;s Developer Connection provides sample code. Their &lt;a href="http://developer.apple.com/samplecode/AbstractTree/"&gt;AbstractTree&lt;/a&gt; demonstrates Core Data, use of bindings along with an &lt;code&gt;NSTreeController&lt;/code&gt;. Download the sample &lt;a href="http://developer.apple.com/samplecode/AbstractTree/AbstractTree.zip"&gt;here&lt;/a&gt; as a ZIP file. It contains two subdirectories: &lt;code&gt;AbstractTree&lt;/code&gt; and &lt;code&gt;Tutorial&lt;/code&gt;. The tutorial is pretty good. It should help you get up-to-speed if you need some familiarity with the basic technology. Build and run the project living under the &lt;code&gt;AbstractTree&lt;/code&gt; folder. It presents you with a window comprising an empty outline view and two buttons.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://pioneeringsoftware.s3.amazonaws.com/blog/2008-09-10_empty_outline_view_with_two_buttons.png" alt="Empty outline view with two buttons" /&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Add&lt;/strong&gt; a few times. You get a series of nested nodes named &amp;#8220;untitled node&amp;#8221;. Quit the application, re-run and you find that, although data saved, the expansion state of the outline view resets. You have to manually expand each item. Of course, you can Option-click the disclosure triangles to auto-expand an item and all its sub-items. But that&amp;#8217;s not really what we want. We want the expand or collapse state of each element displayed in the outline view to &lt;em&gt;persist&lt;/em&gt;! That&amp;#8217;s the goal.&lt;/p&gt;

&lt;p&gt;So far so good. We have a test case that fails. Just what we wanted.&lt;/p&gt;

&lt;h1&gt;Outline view&amp;#8217;s auto-save name&lt;/h1&gt;

&lt;p&gt;Open the sample&amp;#8217;s &lt;code&gt;MainMenu.xib&lt;/code&gt;. Select the &lt;code&gt;NSOutlineView&lt;/code&gt;. Set its &lt;strong&gt;Autosave&lt;/strong&gt; name to (say) &lt;code&gt;Nodes&lt;/code&gt;. Exact value does not matter. This is just a little piece of text for constructing the preferences key. The application&amp;#8217;s defaults will contain an array containing the expanded items. The key will become &amp;#8220;NSOutlineView Items Nodes&amp;#8221; where &lt;code&gt;Nodes&lt;/code&gt; corresponds the the specified &lt;strong&gt;Autosave&lt;/strong&gt; name.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://pioneeringsoftware.s3.amazonaws.com/blog/2008-09-10_autosave_name_of_nodes.png" alt="Autosave name of Nodes" /&gt;&lt;/p&gt;

&lt;p&gt;Leave the &lt;strong&gt;Autosave Expanded Items&lt;/strong&gt; check box &lt;em&gt;unchecked&lt;/em&gt;! Strange but important. If you check this box, the framework resolves the expand-collapse question straightaway. It needs to wait until bindings have been fully established and the data store has been added. The application will instead enable this option programmatically when the application finishes launching. Not before.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://pioneeringsoftware.s3.amazonaws.com/blog/2008-09-10_autosave_expanded_items_check_box_unchecked.png" alt="Autosave Expanded Items check box unchecked" /&gt;&lt;/p&gt;

&lt;h1&gt;Add the new class&lt;/h1&gt;

&lt;p&gt;Add the interface header, &lt;code&gt;RROutlineViewExpandedItemsAutosaver.h&lt;/code&gt;, to the project. Contents as follows. Download header and module sources &lt;a href="http://pioneeringsoftware.s3.amazonaws.com/blog/RROutlineViewExpandedItemsAutosaver.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;AppKit/AppKit.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;------------------------------------------------------------------------------
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; RROutlineViewExpandedItemsAutosaver
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;------------------------------------------------------------------------------
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; This class acts as a "dummy" outline-view data source. Dummy because it does
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; not source any data. But you wire it up as though it did. In reality, its
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; sole purpose is to enable automatic saving of an outline view's expanded
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; items. It sounds counter-intuitive, but you can apply bindings through a tree
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; controller and at the very same time hook up a data source (such as one of
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; these) in order to provide the necessary persistence translations.
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Connect an outline view to an instance of this class. Note, you can connect
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; multiple outlines views to the same instance! The instance carries no
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; state. Message interactions with outline views pass the outline view
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; instance. So no state needed.
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; The implementation makes a number of assumptions. It assumes you connect
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; using bindings to a Core Data model. Hence for every item, it sends [[item
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; representedObject] objectID] which assumes that the represented object
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; responds to -objectID. Core Data's managed objects respond with a unique
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; object identifier.
&lt;/span&gt;
&lt;span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;interface&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;RROutlineViewExpandedItemsAutosaver&lt;/span&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_entity punctuation_definition_entity_other punctuation_definition_entity_other_inherited-class punctuation_definition_entity_other_inherited-class_objc"&gt;:&lt;/span&gt; &lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc"&gt;NSObject&lt;/span&gt;&lt;span class="meta meta_divider meta_divider_objc"&gt;
&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"&gt;&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Add the source module &lt;code&gt;RROutlineViewExpandedItemsAutosaver.m&lt;/code&gt;. Contents follow.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;"&lt;/span&gt;RROutlineViewExpandedItemsAutosaver.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_implementation meta_implementation_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;implementation&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;RROutlineViewExpandedItemsAutosaver&lt;/span&gt;
&lt;span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"&gt;
&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;------------------------------------------------------------------------------
&lt;/span&gt;&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;Outline View Data Source&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;------------------------------------------------------------------------------
&lt;/span&gt;
&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Although linked to the core-data context via bindings and a tree controller,
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; the outline view also has an instance of this object connected to the outline
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; view's data source.
&lt;/span&gt;
&lt;span class="meta meta_function-with-body meta_function-with-body_objc"&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_id storage_type_id_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;outlineView&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSOutlineView&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;outlineView&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;itemForPersistentObject&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_id storage_type_id_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;object&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Iterate all the items. This is not straightforward because the outline
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; view items are nested. So you cannot just iterate the rows. Rows
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; correspond to root nodes only. The outline view interface does not
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; provide any means to query the hidden children within each collapsed row
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; either. However, the root nodes do respond to -childNodes. That makes it
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; possible to walk the tree.
&lt;/span&gt;    &lt;span class="support support_class support_class_cocoa"&gt;NSMutableArray&lt;/span&gt; *items = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSMutableArray&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;array&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    &lt;span class="support support_type support_type_cocoa support_type_cocoa_leopard"&gt;NSInteger&lt;/span&gt; i, rows = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;outlineView &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;numberOfRows&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;for&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;i = &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;; i &amp;lt; rows; i++)
    &lt;span class="meta meta_block meta_block_c"&gt;{
        &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;items &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;addObject&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;outlineView &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;itemAtRow&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;i&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    }&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;for&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;i = &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;items &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;count&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &amp;amp;&amp;amp; !&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;object &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;isEqualToString&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;items &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;objectAtIndex&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;i&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;representedObject&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;objectID&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;URIRepresentation&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;absoluteString&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;; i++)
    &lt;span class="meta meta_block meta_block_c"&gt;{
        &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;items &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;addObjectsFromArray&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;items &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;objectAtIndex&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;i&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;childNodes&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    }&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; i &amp;lt; &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;items &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;count&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; ? &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;items &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;objectAtIndex&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;i&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; : &lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;;
}&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_function-with-body meta_function-with-body_objc"&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_id storage_type_id_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;outlineView&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSOutlineView&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;outlineView&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;persistentObjectForItem&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_id storage_type_id_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;item&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; "Persistent object" means a unique representation of the item's object,
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; representing the objects identity, not its state. Outline view writes
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; this to user defaults as soon as the item expands. That's when it asks
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; for the persistent object, sending -outlineView:persistentObjectForItem:
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; and execution arrives here. A minor problem arises when adding new
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; items. The new item represents a new unsaved managed object. The managed
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; object only has a temporary object identifier. It will receive a
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; permanent one when saved. So, if the objectID answers a temporary one,
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; ask the context to save and re-request the objectID. The second request
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; gives a permanent identifier, assuming saving succeeds. Don't worry about
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; committing unsaved edits at this point.
&lt;/span&gt;    NSManagedObject *object = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;item &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;representedObject&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    NSManagedObjectID *objectID = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;object &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;objectID&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;objectID &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;isTemporaryID&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;)
    &lt;span class="meta meta_block meta_block_c"&gt;{
        &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;!&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;object &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;managedObjectContext&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;save&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="constant constant_language constant_language_c"&gt;NULL&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;)
        &lt;span class="meta meta_block meta_block_c"&gt;{
            &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; &lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;;
        }&lt;/span&gt;
        objectID = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;object &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;objectID&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    }&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;objectID &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;URIRepresentation&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;absoluteString&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
}&lt;/span&gt;&lt;/span&gt;

&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Add this header and module to the project, under the Classes group. An instance of this class will become the new data source for the outline view.&lt;/p&gt;

&lt;h2&gt;Add the new data-source&lt;/h2&gt;

&lt;p&gt;Add a new instance of &lt;code&gt;RROutlineViewExpandedItemsAutosaver&lt;/code&gt; to the nib and connect the new instance to the &lt;code&gt;NSOutlineView&lt;/code&gt; as the outline view&amp;#8217;s &lt;code&gt;dataSource&lt;/code&gt;. Use Interface Builder. Drag an Object from the palette to the nib. Change its class in the Identity Inspector panel (Command-6). Then connect the &lt;code&gt;NSOutlineView&lt;/code&gt; to it as the new data source. It replaces the pre-existing connection between outline view and app delegate.&lt;/p&gt;

&lt;p&gt;After this, the nib is ready.&lt;/p&gt;

&lt;h1&gt;App delegate&lt;/h1&gt;

&lt;p&gt;Apple have used the standard Core Data application delegate. It builds a managed object model, persistent store co-ordinator and managed object context. The classic Core Data stack! Our changes need to add a message-send for enabling auto-save expanded items to the outline view. But it&amp;#8217;s not the only change required.&lt;/p&gt;

&lt;p&gt;There is a subtle problem. It concerns bindings and Core Data. The important requirement is that when the outline view tries to restore auto-saved expanded items, the outline view has its items already loaded. Otherwise how can it translate &amp;#8220;persistent objects&amp;#8221; to items. Persistent objects, in this context, refers to keys used in the application defaults to identify the set of expanded items; everything not expanded defaults to collapsed.&lt;/p&gt;

&lt;h2&gt;Moving where the application adds its persistent store&lt;/h2&gt;

&lt;p&gt;When the application loads, it automatically loads &lt;code&gt;MainMenu&lt;/code&gt; nib. All the object instances therein become instantiated. Indirectly, the managed object context and its other Core Data stack components come to life at this time. Therein lies the subtle problem. The Cocoa framework will not immediately load the Core Data objects if the context already has its store when nib-loading establishes the bindings. That&amp;#8217;s a mouthful. Basically, the order must go:
1. Establish bindings. Do this wholesale.
2. Add persistent store. At this point, the outline view grabs its contents through bindings to the tree controller.
3. Enable auto-save expanded items.&lt;/p&gt;

&lt;p&gt;Simplify the &lt;code&gt;-persistentStoreCoordinator&lt;/code&gt; implementation to:&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;- (NSPersistentStoreCoordinator *)persistentStoreCoordinator &lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;persistentStoreCoordinator == &lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;) &lt;span class="meta meta_block meta_block_c"&gt;{
        persistentStoreCoordinator = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;NSPersistentStoreCoordinator &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;alloc&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;
            initWithManagedObjectModel:&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="variable variable_language variable_language_objc"&gt;self&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;managedObjectModel&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    }&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; persistentStoreCoordinator;
}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And second, add a new method:&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;- (&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;)applicationDidFinishLaunching:(&lt;span class="support support_class support_class_cocoa"&gt;NSNotification&lt;/span&gt; *)notification
&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="support support_class support_class_cocoa"&gt;NSFileManager&lt;/span&gt; *fileManager;
    &lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *applicationSupportFolder = &lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;;
    &lt;span class="support support_class support_class_cocoa"&gt;NSURL&lt;/span&gt; *url;
    &lt;span class="support support_class support_class_cocoa"&gt;NSError&lt;/span&gt; *error;

    fileManager = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSFileManager&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;defaultManager&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    applicationSupportFolder = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="variable variable_language variable_language_objc"&gt;self&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;applicationSupportFolder&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;!&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;fileManager &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;fileExistsAtPath&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;applicationSupportFolder &lt;span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc"&gt;isDirectory&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="constant constant_language constant_language_c"&gt;NULL&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;) &lt;span class="meta meta_block meta_block_c"&gt;{
        &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;fileManager &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;createDirectoryAtPath&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;applicationSupportFolder &lt;span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc"&gt;attributes&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    }&lt;/span&gt;

    url = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSURL&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;fileURLWithPath&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;applicationSupportFolder
        stringByAppendingPathComponent:&lt;span class="string string_quoted string_quoted_double string_quoted_double_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc"&gt;@"&lt;/span&gt;AbstractTree.xml&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;!&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="variable variable_language variable_language_objc"&gt;self&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;persistentStoreCoordinator&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;
        addPersistentStoreWithType:NSXMLStoreType
                     configuration:&lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;
                               URL:url
                           options:&lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;
                             error:&amp;amp;error&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;) &lt;span class="meta meta_block meta_block_c"&gt;{
        &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSApplication&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;sharedApplication&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;presentError&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;error&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    }&lt;/span&gt;    
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Watch out for this! Make sure that the data is available before enabling
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; auto-save for expanded items. You can switch it on within the nib. Problem
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; though is that the data store must be available at nib awaking time!
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Otherwise, how can the auto-saving of expanded items compare against
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; existing items in order to determine whether or not they should be restored
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; as expanded or not.
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; There's another caveat. You need to let the bindings make the necessary
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; connections first, before connecting the Core Data context and persistent
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; store coordinator to the store. In other words, the store must be added
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; last. Here is a good place. Application-did-finish-launching occurs after
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; all nib awaking methods, after bindings have been established. Hence, when
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; the store gets added, the outline view immediately sees the contents
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; through its bindings. Otherwise the outline-view expanded items auto-saver
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; cannot see the items at all.
&lt;/span&gt;    &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;outlineView &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;setAutosaveExpandedItems&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="constant constant_language constant_language_objc"&gt;YES&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
}&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That&amp;#8217;s it!&lt;/p&gt;

&lt;h1&gt;Successful test&lt;/h1&gt;

&lt;p&gt;Build and go. This time, when you expand nodes, quit then re-run, the sample correctly expands the previously-expanded items. Great. You can view the sample application&amp;#8217;s user defaults by typing, in Terminal:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;defaults read com.apple.dts.AbstractTreeApp
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It will list the saved expanded items array, resembling something along these lines:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
    "NSOutlineView Items Nodes" =     (
        "x-coredata://68A35129-6EA4-45E7-B3FB-F1C15FDC02D9/Node/p104",
        "x-coredata://68A35129-6EA4-45E7-B3FB-F1C15FDC02D9/Node/p102"
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Download the complete sample project &lt;a href="http://pioneeringsoftware.s3.amazonaws.com/blog/AbstractTree.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/zcJ6Km6LI6k" height="1" width="1"/&gt;</description>
      <pubDate>Wed, 10 Sep 2008 07:42:56 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:09ce9a4f-24c3-4fa9-a2f5-743a709dfb25</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2008/09/10/outline-view-tree-controller-and-itemforpersistentobject#comments</comments>
      <category>AppKit</category>
      <category>view</category>
      <category>controller</category>
      <category>core</category>
      <category>data</category>
      <category>outline</category>
      <category>tree</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=13</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/zcJ6Km6LI6k/outline-view-tree-controller-and-itemforpersistentobject</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2008/09/10/outline-view-tree-controller-and-itemforpersistentobject</feedburner:origLink></item>
    <item>
      <title>Organising view controllers, continued</title>
      <description>&lt;p&gt;The last article on this subject (&lt;a href="http://blog.pioneeringsoftware.co.uk/2008/08/29/organising-view-controllers"&gt;Organising view controllers&lt;/a&gt;) started looking at an example. Apple&amp;#8217;s ViewController sample illustrates basic use of multiple view controllers. This article completes the work.&lt;/p&gt;

&lt;p&gt;Download the &lt;a href="http://pioneeringsoftware.s3.amazonaws.com/blog/View_Controller_Mark_II.zip"&gt;source&lt;/a&gt; if you would rather skip ahead. Sometimes it&amp;#8217;s easier that way. You can see the code in its full context. Snippets and extracts don&amp;#8217;t always tell you everything you need to know.&lt;/p&gt;

&lt;h1&gt;Missing pieces&lt;/h1&gt;

&lt;p&gt;Where did we leave off? Application delegate and window controller exist but don&amp;#8217;t do much. The window controller has a stub for the pop-up action. It does nothing. Of course, the application needs some custom view controllers for handling the view-specific behaviours. The image view has an Open push-button for example. Click this and the controller presents an Open Panel letting the user change the view&amp;#8217;s image. Lake Don Pedro looks nice, but perhaps you fancy a change! The table view initialises some names, etc. Custom view controllers will add the view-specific controller behaviour.&lt;/p&gt;

&lt;p&gt;However, the biggest missing piece: the view meta-controller itself. The project needs a class for meta-controlling view controllers.&lt;/p&gt;

&lt;h1&gt;Start simple&lt;/h1&gt;

&lt;p&gt;What is the most basic requirement? Our test application (View Controller Mark II) wants to say &amp;#8220;load a view&amp;#8221; given by &lt;code&gt;@"CustomImageView"&lt;/code&gt;, a string. The meta-control architecture then loads the corresponding nib, constructs an instance of &lt;code&gt;CustomImageViewController&lt;/code&gt; and then hangs the result in a &lt;em&gt;graph&lt;/em&gt; of meta-controllers. At any time thereafter, any object method with access to the meta-control graph can access the view controller (i.e. &lt;code&gt;[vmc viewControllerForViewPath:@"CustomImageView"]&lt;/code&gt; where &lt;code&gt;vmc&lt;/code&gt; means the view meta-controller) and, from there, its view, represented object and title. Note, if there were nested sub-controllers, the view-path would read &lt;code&gt;@"CustomImageView.SomeOtherName"&lt;/code&gt;. SomeOtherName stands for a nested tier of control. In this case though, requirements only need non-nested controllers. Pity.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s take the &lt;code&gt;NSViewController&lt;/code&gt; class and bolt on a meta-controller. The new class associates with one view controller (its subordinate controller) and multiple subordinate meta-controllers by name. See diagram below.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://pioneeringsoftware.s3.amazonaws.com/blog/2008-08-31_view_meta_controller_class_diagram.png" alt="View Meta Controller class diagram" /&gt;&lt;/p&gt;

&lt;p&gt;The diagram indicates unidirectional associations using directed arrows. The &lt;code&gt;viewController&lt;/code&gt; association from meta-controller to view controller is unidirectional, in that direction. Likewise from name to subordinate meta-controller. Names are unique strings identifying lower levels of meta-control. This model forms a graph or tree: a hierarchy of named meta-controllers.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s a simple model. Note, no reverse navigation from view controller to meta-controller. Hence no need for new &lt;code&gt;NSViewController&lt;/code&gt; subclasses. The hierarchy lives outside the pre-existing view controller framework. Of course, the model supports view controller subclasses, but not for maintaining the meta-control graph.&lt;/p&gt;

&lt;p&gt;You might have noticed the diamond shape at the name-end of the meta-controller association; it marks an aggregation. In fact, in this case, it marks a self-aggregation, also known as circular. Some sources say that self-aggregation does not make sense. I&amp;#8217;m not so sure. In this instance, meta-controllers are &amp;#8220;parts of&amp;#8221; other meta-controllers. Aggregation is not a precise concept. Suffices to say there is a strong association between meta-controller parts.&lt;/p&gt;

&lt;h1&gt;Overlaying some methods&lt;/h1&gt;

&lt;p&gt;Of course, the diagram above shows &lt;code&gt;RRViewMetaController&lt;/code&gt; without methods. So not a very useful class, at present.&lt;/p&gt;

&lt;p&gt;Adding methods can prove challenging. It takes judgement, experience, skill, even art. There is never one &amp;#8220;right&amp;#8221; way. It&amp;#8217;s almost like pouring custard over your pudding! You don&amp;#8217;t want a thick blob at one side; a smooth even coating works best. Yes, I know, that carries it too far. But I&amp;#8217;m sure you know what I mean: behaviour needs judicious placement within a class structure. Methods are little packets of behaviour. Placing them, naming them is as important as implementing them, because in the long run mistakes can have an important impact on maintenance. When the custard goes cold, it gets harder to spread. I&amp;#8217;ll shut up about custard now (I must be hungry though I just ate).&lt;/p&gt;

&lt;p&gt;Meta-control will need methods for the following function groups.&lt;/p&gt;

&lt;h2&gt;Initialising and de-allocating&lt;/h2&gt;

&lt;p&gt;The usual housekeeping work.
* &lt;code&gt;-init&lt;/code&gt; initialises an instance
* &lt;code&gt;-dealloc&lt;/code&gt; de-allocates an instance&lt;/p&gt;

&lt;h2&gt;Accessing properties&lt;/h2&gt;

&lt;p&gt;Every meta-controller controls a subordinate view controller. Other objects need access to this.
* &lt;code&gt;-viewController&lt;/code&gt; answers the associated view controller
* &lt;code&gt;-view&lt;/code&gt; answers the view controller&amp;#8217;s view&lt;/p&gt;

&lt;h2&gt;Adding and removing from super-views&lt;/h2&gt;

&lt;p&gt;Every meta-controller directly and indirectly manages a triplet: a view controller, a nib and a view hierarchy. The view hierarchy does not automatically enter any given window undirected. The design requires methods for adding and removing the view, along with any sub-views.
* &lt;code&gt;-addToSuperview:aSuperview&lt;/code&gt; adds the meta-controlled view to &lt;code&gt;aSuperview&lt;/code&gt;
* &lt;code&gt;-removeFromSuperview&lt;/code&gt; removes the meta-controlled view from its super-view&lt;/p&gt;

&lt;h2&gt;Naming and removing meta-controllers&lt;/h2&gt;

&lt;p&gt;Accessing meta-controllers&amp;#8217; names, removing them if necessary.
* &lt;code&gt;-namesOfMetaControllers&lt;/code&gt; gives all the names of the subordinate meta-controllers
* &lt;code&gt;-nameOfMetaController:aMetaController&lt;/code&gt; answers the name of &lt;code&gt;aMetaController&lt;/code&gt;
* &lt;code&gt;-removeMetaController:aMetaController&lt;/code&gt; removes &lt;code&gt;aMetaController&lt;/code&gt; by identity&lt;/p&gt;

&lt;h2&gt;Resolving and removing view paths&lt;/h2&gt;

&lt;p&gt;Given view-path strings, meta-controller instances answer corresponding controllers, loading view controllers and views as necessary.
* &lt;code&gt;-resolveViewPath:aViewPath&lt;/code&gt; resolves a view path answering an array of meta-controllers
* &lt;code&gt;-removeViewPath:aViewPath&lt;/code&gt; removes the meta-controller identified by &lt;code&gt;aViewPath&lt;/code&gt;
* &lt;code&gt;-viewMetaControllerForViewPath:aViewPath&lt;/code&gt; answers the view meta-controller identified by &lt;code&gt;aViewPath&lt;/code&gt;
* &lt;code&gt;-viewControllerForViewPath:aViewPath&lt;/code&gt; shortcuts the view controller accessor, answering a view controller for a given view path&lt;/p&gt;

&lt;p&gt;Adding these to the class diagram:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://pioneeringsoftware.s3.amazonaws.com/blog/2008-09-02_view_meta_controller_class_diagram_ii.png" alt="View Meta Controller class diagram (ii)" /&gt;&lt;/p&gt;

&lt;p&gt;Notice the method signatures reflect C++ and Java language styling. Method name comes before arguments and arguments appear in parentheses. Of course, in real life, Objective-C intermingles signature and arguments. Hence you see &lt;code&gt;addToSuperview:&lt;/code&gt; as the name, with &lt;code&gt;aSuperView&lt;/code&gt; : &lt;code&gt;NSView&lt;/code&gt; as the argument-and-type pair. I&amp;#8217;ve also skipped the pointer asterisk as implied. I hope it makes sense. Note also, plus prefix means public in this context, not a class method.&lt;/p&gt;

&lt;h1&gt;Interface, RRViewMetaController.h&lt;/h1&gt;

&lt;p&gt;Turning the requirements into Objective-C:&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;AppKit/AppKit.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Meta refers to a position beyond, of a higher or second-order kind. Thus, a
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; meta-controller controls controllers! Hence, the view meta-controller class
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; controls view controllers.
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Notice, the class does not implement a back-reference to the parent
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; meta-controller. True, even though they form a tree. View paths specify leaf
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; nodes. The class resolves the path by walking from root to leaf, recording
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; the journey at each step. This approach obviates references to parent nodes.
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Effectively, the graph of meta-controllers "hovers" above the view
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; controllers, retaining them and their view hierarchies. You address leaves on
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; the meta-graph using view paths where the names of the path elements
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; correspond to the nib names. That implies that you can have the same nib by
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; the same name. You can but not at the same tier in the hierarchy unless you
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; use a colon to add more context to the name without adding to the nib
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; name. In short, name strings of the form myNib:blahBlah loads the nib file
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; named myNib but uses myNib:blahBlah to uniquely identify the meta-controller
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; within the graph.
&lt;/span&gt;&lt;span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;interface&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;RRViewMetaController&lt;/span&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_entity punctuation_definition_entity_other punctuation_definition_entity_other_inherited-class punctuation_definition_entity_other_inherited-class_objc"&gt;:&lt;/span&gt; &lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc"&gt;NSObject&lt;/span&gt;&lt;span class="meta meta_divider meta_divider_objc"&gt;
&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"&gt;&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="support support_class support_class_cocoa"&gt;NSMutableDictionary&lt;/span&gt; *metaControllersByName;
    &lt;span class="support support_class support_class_cocoa support_class_cocoa_leopard"&gt;NSViewController&lt;/span&gt; *viewController;
}&lt;/span&gt;

&lt;span class="meta meta_property-with-attributes meta_property-with-attributes_objc"&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc"&gt;@&lt;/span&gt;property&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;(&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_property keyword_other_property_attribute"&gt;retain&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class="support support_class support_class_cocoa support_class_cocoa_leopard"&gt;NSViewController&lt;/span&gt; *viewController;

&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;------------------------------------------------- Initialisers &amp;amp; De-Allocators
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;releaseViewController&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Releases the associated view controller and by implication also removes
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; the view controller's view from its super-view.
&lt;/span&gt;
&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;-------------------------------------------------------------------- Accessors
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSView&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;view&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Every meta-controller stands in the shadow of a view controller, an
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; instance of NSViewController. Every view controller associates with a
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; view. The meta-controller's -view method (this method) answers the
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; view. If not already loaded from its nib, this method also indirectly
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; does so.
&lt;/span&gt;
&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;---------------------------------------- Adding to &amp;amp; Removing from Super-Views
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;addToSuperview&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSView&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;superview&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Adds the view linked to this meta-controller (via the view controller) to
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; the given super-view. The controlled sub-view's frame becomes equal to
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; the super-view's bounds. This is a simple approach to layout.
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;removeFromSuperview&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Removes the meta-controlled view from its super-view, but without
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; releasing the view controller.
&lt;/span&gt;
&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;------------------------------------------- Naming &amp;amp; Removing Meta-Controllers
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSArray&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;namesOfMetaControllers&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Answers all the unique names of the subordinate meta-controllers.
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;nameOfMetaController&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;RRViewMetaController *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;metaController&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Answers the name of the given meta-controller. Assumes that the given
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; object is a direct child node of the receiving meta-controller. Returns
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; nil of not. Names are unique. Meta-controllers can only have one for each
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; subordinate meta-controller.
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;removeMetaController&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;RRViewMetaController *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;metaController&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Removes a meta-controller by its identity; the argument specifies a
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; meta-controller identity by pointer. Take care to retain the
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; meta-controller if necessary before removing.
&lt;/span&gt;
&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt;---------------------------------------------- Resolving &amp;amp; Removing View Paths
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSArray&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;resolveViewPath&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;viewPath&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Resolves a given view path answering an array of view
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; meta-controllers. The method automatically constructs any missing
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; controller elements, if any. The given path applies relatively with
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; respect to the receiver. If the path specifies sub-controllers, resolving
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; continues by recursion. Note that resolving a view path constructs the
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; corresponding meta-controllers but does not automatically load the
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; corresponding views. Accessing a view controller's view method loads the
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; view.
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;removeViewPath&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;viewPath&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Removes the meta-controller identified by the given
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; view-path. Presumably, the application has already resolved the
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; path. Otherwise, resolving herein will first construct the path before
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; removing it. The path specifies a leaf in the meta-control
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; graph. Removing releases and removes the leaf only. It does not remove
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; any elements in-between the removed leaf and the root.
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;RRViewMetaController *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;viewMetaControllerForViewPath&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;viewPath&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Answers the view meta-controller for a given view-path. It's a
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; convenience method, equivalent to resolving the path, then picking the
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; leaf node equal to the last element resolved.
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa support_class_cocoa_leopard"&gt;NSViewController&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;viewControllerForViewPath&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;viewPath&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Handy shortcut for asking for a meta-controller by view-path then asking
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; the meta-controller for its view controller.
&lt;/span&gt;
&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I&amp;#8217;ve included comments describing the class and its methods. They might be worth reading. I know you&amp;#8217;d rather skip. Anyway, notice the method groups.&lt;/p&gt;

&lt;p&gt;Resolving view paths, that&amp;#8217;s the key method. Given a view-path string, it answers an array of meta-controllers, one for each name appearing in the path. For example, given a string such as &lt;code&gt;@"a.b.c"&lt;/code&gt;, the &lt;code&gt;-resolveViewPath:&lt;/code&gt; instance method walks the meta-controller graph starting at &lt;code&gt;a&lt;/code&gt;, then subordinate &lt;code&gt;b&lt;/code&gt;, followed finally by &lt;code&gt;c&lt;/code&gt;. Resolving constructs the graph along the way. Dots in the view-path string delimit meta-controller names. Names must be unique and correspond to nib names. Loading &lt;code&gt;a&lt;/code&gt; looks for a nib named &lt;code&gt;@"a"&lt;/code&gt;. You reuse nibs using a colon in the name, e.g. view-path of &lt;code&gt;@"a:1"&lt;/code&gt; and &lt;code&gt;@"a:2"&lt;/code&gt; resolve to the same nib (&lt;code&gt;a&lt;/code&gt;) but have unique meta-controller names. Everything after the colon belongs to the unique meta-controller name. Everything before identifies the nib.&lt;/p&gt;

&lt;p&gt;In the next article on this subject, I&amp;#8217;ll deal with the implementation.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/loU1YUTQav8" height="1" width="1"/&gt;</description>
      <pubDate>Mon, 01 Sep 2008 16:59:24 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:8f812a11-c24f-412e-9138-e9094bd9cfe7</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2008/09/01/organising-view-controllers-continued#comments</comments>
      <category>AppKit</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=12</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/loU1YUTQav8/organising-view-controllers-continued</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2008/09/01/organising-view-controllers-continued</feedburner:origLink></item>
    <item>
      <title>Organising view controllers</title>
      <description>&lt;p&gt;Understanding how individual view controllers work is one thing. Organising them is another. Applications typically deal with multiple view controllers. Views can change dynamically. Hence view controllers need dynamic capabilities.&lt;/p&gt;

&lt;p&gt;This article presents an idea for organising view controllers within an application. Design goals include: flexibility, simplicity, convention over configuration.&lt;/p&gt;

&lt;h1&gt;View paths&lt;/h1&gt;

&lt;p&gt;The design idea centres around the concept of a &lt;em&gt;view path&lt;/em&gt;. Paths are a ubiquitous paradigm. You find them in file systems, graphs, in Cocoa&amp;#8217;s key-value coding, in X-Path querying, the list goes on. &lt;em&gt;Graph&lt;/em&gt; is the underlying structure (directed acyclic, to be technical). Paths express a route between two points in the graph, from the root to some leaf node for example.&lt;/p&gt;

&lt;p&gt;View hierarchies form such a nested model, so applying paths naturally expresses the intrinsic nested construct. Simple notion then: View hierarchy equals graph, use path to navigate it. Stay with me. You&amp;#8217;ll see where I&amp;#8217;m going.&lt;/p&gt;

&lt;h1&gt;Meta-control&lt;/h1&gt;

&lt;p&gt;Meta is a funny word. &amp;#8220;It&amp;#8217;s from the Greek,&amp;#8221; in a Greek accent! Here it refers to things beyond or above, a higher order. View controllers control their views, yes. But what controllers the controller? Answer: some form a meta-control, controlling the control. It makes the head spin. Yet necessary. Every application, large and small, requires some form of overarching control, or, in object terms, some framework on which to overlay the flesh of behaviour.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m being a little cryptic. Are you following me?&lt;/p&gt;

&lt;p&gt;So. Let&amp;#8217;s assume: one view, one view controller. &amp;#8220;View&amp;#8221; here refers to a view sub-hierarchy, one that you load from a nib; so it might comprise many sub-views but has one container view. Our application wants to manage a hierarchy of such controller-view-nib triplets.&lt;/p&gt;

&lt;p&gt;Tempting to directly overlay a tree structure by sub-classing a new view controller class, adding an array of view sub-controllers. A simple approach, but limiting. It forces the view controllers into a strict hierarchy. This does not fit the requirement for flexibility. It inserts the meta-controlling layer into the low-order control layer. A flexible solution really needs a second-order of controlling existing &lt;em&gt;above&lt;/em&gt; the first rather than intermingled.&lt;/p&gt;

&lt;h1&gt;Show me the money&lt;/h1&gt;

&lt;p&gt;So far, we&amp;#8217;ve been living in the abstract. Reality doesn&amp;#8217;t live there. Let&amp;#8217;s get practical. Take an example.&lt;/p&gt;

&lt;p&gt;Start an experiment. Take Apple&amp;#8217;s &lt;a href="http://developer.apple.com/samplecode/ViewController/"&gt;ViewController&lt;/a&gt; sample code (screen shot below) as the reference point. Let&amp;#8217;s try to improve it. Can we reduce the number of lines? Make it easier to understand, maintain, expand? Seems like a tall order. Too tall?&lt;/p&gt;

&lt;p&gt;&lt;img src="http://pioneeringsoftware.s3.amazonaws.com/blog/2008-08-28_viewcontroller_sample_code.png" alt="ViewController sample code" /&gt;&lt;/p&gt;

&lt;p&gt;As you see, there&amp;#8217;s a large custom view in the upper portion of the window. Clicking the pop-up button presents you with four choices. The choice switches the custom view. Four different sets of view controller, nib and sub-view switch in and out accordingly.&lt;/p&gt;

&lt;h2&gt;Lies, lies and statistics&lt;/h2&gt;

&lt;p&gt;Improvement is hard to measure. &lt;em&gt;Better&lt;/em&gt; is a subjective term. My better and your better might not be the same better. So for the experiment, we will add some objectivity. Start by measuring the existing ViewController project.&lt;/p&gt;

&lt;p&gt;Basic software metric: lines of source code (SLOC).&lt;/p&gt;

&lt;p&gt;The &lt;a href="http://cloc.sourceforge.net/"&gt;&lt;code&gt;cloc&lt;/code&gt;&lt;/a&gt; tool reports:&lt;/p&gt;

&lt;pre&gt;
-------------------------------------------------------------------------------
Language          files     blank   comment      code    scale   3rd gen. equiv
-------------------------------------------------------------------------------
Objective C          11       165       502       229 x   2.96 =         677.84
-------------------------------------------------------------------------------
SUM:                 11       165       502       229 x   2.96 =         677.84
-------------------------------------------------------------------------------
&lt;/pre&gt;


&lt;p&gt;229 lines of code in total. I&amp;#8217;m running &lt;code&gt;cloc&lt;/code&gt; from the ViewController project directory and passing arguments &amp;#8221;&lt;code&gt;--force-lang="Objective C",h .&lt;/code&gt;&amp;#8221; meaning that source files with &lt;code&gt;h&lt;/code&gt; classify as Objective C; dot refers to the current working directory, of course.&lt;/p&gt;

&lt;p&gt;Adding the &lt;code&gt;--by-file&lt;/code&gt; option produces some interesting statistics too.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;-------------------------------------------------------------------------------
File                        blank   comment      code    scale   3rd gen. equiv
-------------------------------------------------------------------------------
./MyWindowController.m         30        64        92 x   2.96 =         272.32
./CustomImageViewController.m  17        58        37 x   2.96 =         109.52
./AppDelegate.m                17        50        24 x   2.96 =          71.04
./CustomVideoViewController.m  15        46        18 x   2.96 =          53.28
./CustomTableViewController.m  13        44        17 x   2.96 =          50.32
./MyWindowController.h         13        40         9 x   2.96 =          26.64
./CustomImageViewController.h  13        40         8 x   2.96 =          23.68
./AppDelegate.h                12        40         7 x   2.96 =          20.72
./CustomVideoViewController.h  12        40         6 x   2.96 =          17.76
./CustomTableViewController.h  12        40         6 x   2.96 =          17.76
./main.m                       11        40         5 x   2.96 =          14.80
-------------------------------------------------------------------------------
SUM:                          165       502       229 x   2.96 =         677.84
-------------------------------------------------------------------------------
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we see that most of the complexity (in lines-of-code terms anyway) resides in the window controller implementation: 92 lines of code, top of the list. That&amp;#8217;s likely where one might expect greater complexity. But on the other hand, shouldn&amp;#8217;t the view controller paradigm mitigate window controller complexity to some degree. We shall see.&lt;/p&gt;

&lt;h3&gt;Cash register&lt;/h3&gt;

&lt;p&gt;Let&amp;#8217;s also use David A. Wheeler&amp;#8217;s &lt;a href="http://www.dwheeler.com/sloccount/"&gt;SLOCCount&lt;/a&gt; tool. It&amp;#8217;s easy to install using &lt;a href="http://www.macports.org/"&gt;MacPorts&lt;/a&gt;. Just enter &lt;code&gt;sudo port install sloccount&lt;/code&gt; in Terminal. After installing, entering &amp;#8221;&lt;code&gt;sloccount .&lt;/code&gt;&amp;#8221; in the &lt;code&gt;ViewController&lt;/code&gt; project directory gives:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Total Physical Source Lines of Code (SLOC)                = 246
Development Effort Estimate, Person-Years (Person-Months) = 0.05 (0.55)
 (Basic COCOMO model, Person-Months = 2.4 * (KSLOC**1.05))
Schedule Estimate, Years (Months)                         = 0.17 (1.99)
 (Basic COCOMO model, Months = 2.5 * (person-months**0.38))
Estimated Average Number of Developers (Effort/Schedule)  = 0.28
Total Estimated Cost to Develop                           = $ 6,196
 (average salary = $56,286/year, overhead = 2.40).
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Phew! 246 lines costing 6,000 dollars. Interesting that the number of lines do not agree. SLOCCount counts some of the comment lines. Big question is: can our experiment save bucks?&lt;/p&gt;

&lt;h1&gt;Let the games begin&lt;/h1&gt;

&lt;p&gt;Start with a new project. Use the Cocoa Application template: not document based, without Core Data. I&amp;#8217;ll call it &lt;em&gt;View Controller Mark II&lt;/em&gt;! That sounds Spitfire-esque. Excuse the appeal to glamour and (apparent) adventure. Just hope it doesn&amp;#8217;t crash!&lt;/p&gt;

&lt;p&gt;The new empty project provides just 5 lines of code in &lt;code&gt;main.m&lt;/code&gt;. We have a blank &lt;code&gt;MainMenu.xib&lt;/code&gt; too; just the main menu and main window. No application delegate, no window controller. Yet.&lt;/p&gt;

&lt;p&gt;Rather than re-create the nibs, the experiment will just copy them from Apple&amp;#8217;s sample code verbatim. That way, the comparison will be like-for-like. Only Objective-C code will change. Nothing else. So, delete &lt;code&gt;MainMenu.xib&lt;/code&gt;; &lt;code&gt;MainMenu.nib&lt;/code&gt; will replace it. Add to Resources: four Custom View nibs, &lt;code&gt;MainMenu&lt;/code&gt; and &lt;code&gt;TestWindow&lt;/code&gt; nibs. Add with Copy enabled. The custom video view uses &lt;code&gt;QTMovieView&lt;/code&gt; so the project needs &lt;code&gt;QTKit&lt;/code&gt; framework adding too. Add &lt;code&gt;Quartz&lt;/code&gt; while we&amp;#8217;re at it; the camera view uses Quartz&amp;#8217;s &lt;code&gt;QCView&lt;/code&gt;. The Lake Don Pedro JPEG image and QuickTime movie needs adding, finally.&lt;/p&gt;

&lt;p&gt;Build already? No. It cannot run yet. Missing &lt;code&gt;AppDelegate&lt;/code&gt; for one thing. After launch, the application delegate needs to create a new window controller (a custom one) and initialise it using the &lt;code&gt;TestWindow&lt;/code&gt; nib.&lt;/p&gt;

&lt;p&gt;So, we sub-class &lt;code&gt;NSWindowController&lt;/code&gt; as &lt;code&gt;MyWindowController&lt;/code&gt;. Add the necessary instance variables, &lt;code&gt;myTargetView&lt;/code&gt; and &lt;code&gt;viewController&lt;/code&gt;; add the &lt;code&gt;(IBAction)viewChoicePopupAction:(id)sender&lt;/code&gt; instance method. That makes the project build and run, though do nothing remarkable of course.&lt;/p&gt;

&lt;p&gt;By the time building and running reaches an error-free level of success, application delegate and window controller sources appear as follows.&lt;/p&gt;

&lt;h2&gt;Barebones application delegate&lt;/h2&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;Cocoa/Cocoa.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;class&lt;/span&gt; MyWindowController;

&lt;span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;interface&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;AppDelegate&lt;/span&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_entity punctuation_definition_entity_other punctuation_definition_entity_other_inherited-class punctuation_definition_entity_other_inherited-class_objc"&gt;:&lt;/span&gt; &lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc"&gt;NSObject&lt;/span&gt;&lt;span class="meta meta_divider meta_divider_objc"&gt;
&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"&gt;&lt;span class="meta meta_block meta_block_c"&gt;{
    MyWindowController *myWindowController;
}&lt;/span&gt;
&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;It&amp;#8217;s implementation:&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;"&lt;/span&gt;AppDelegate.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;"&lt;/span&gt;MyWindowController.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_implementation meta_implementation_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;implementation&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;AppDelegate&lt;/span&gt;
&lt;span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"&gt;
&lt;span class="meta meta_function-with-body meta_function-with-body_objc"&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;IBAction&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;newDocument&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_id storage_type_id_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;sender&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; The MainMenu nib's main menu sends this action when you select File New,
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; or Command+N. The menu item target is the first responder. This falls
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; through the Responder Chain until it finally hits AppDelegate. Answer by
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; constructing the window controller, if not already existing, and show it.
&lt;/span&gt;    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_initialization meta_initialization_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;/span&gt;myWindowController == &lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;)
        myWindowController = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;MyWindowController &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;alloc&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;initWithWindowNibName&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc"&gt;@"&lt;/span&gt;TestWindow&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;myWindowController &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;showWindow&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="variable variable_language variable_language_objc"&gt;self&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
}&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_function-with-body meta_function-with-body_objc"&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;applicationDidFinishLaunching&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSNotification&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;notification&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; By virtue of AppDelegate being the application's delegate, it
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; automatically receives application notifications. How kind. Respond by
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; sending the -newDocument: action, just as if the user pressed Command+N.
&lt;/span&gt;    &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc"&gt;[&lt;/span&gt;&lt;span class="variable variable_language variable_language_objc"&gt;self&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;newDocument&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="variable variable_language variable_language_objc"&gt;self&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
}&lt;/span&gt;&lt;/span&gt;

&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Barebones window controller&lt;/h2&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;Cocoa/Cocoa.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;interface&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;MyWindowController&lt;/span&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_entity punctuation_definition_entity_other punctuation_definition_entity_other_inherited-class punctuation_definition_entity_other_inherited-class_objc"&gt;:&lt;/span&gt; &lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc"&gt;NSWindowController&lt;/span&gt;&lt;span class="meta meta_divider meta_divider_objc"&gt;
&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"&gt;&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="storage storage_type storage_type_objc"&gt;IBOutlet&lt;/span&gt; &lt;span class="support support_class support_class_cocoa"&gt;NSView&lt;/span&gt; *myTargetView;
    &lt;span class="support support_class support_class_cocoa support_class_cocoa_leopard"&gt;NSViewController&lt;/span&gt; *viewController;
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; TestWindow.nib contains bindings to this instance variable's "title"
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; and "representedObject" property. Rather than naming it
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; myCustomViewController, as does the Apple sample code, name the
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; instance variable by its KVC key. Doing so saves an accessor.
&lt;/span&gt;}&lt;/span&gt;

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;IBAction&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;viewChoicePopupAction&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_id storage_type_id_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;sender&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;

&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And its implementation:&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;"&lt;/span&gt;MyWindowController.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_implementation meta_implementation_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;implementation&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;MyWindowController&lt;/span&gt;
&lt;span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"&gt;
&lt;span class="meta meta_function-with-body meta_function-with-body_objc"&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;IBAction&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;viewChoicePopupAction&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_id storage_type_id_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;sender&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class="meta meta_block meta_block_c"&gt;{
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; TestWindow nib connects action -viewChoicePopupAction: to the window
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; controller. MyWindowController is the nib's owner. The
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Image-Table-Video-Camera pop-up button sends this action to the nib
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; owner. The window controller responds by switching view and view
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; controller.
&lt;/span&gt;}&lt;/span&gt;&lt;/span&gt;

&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;At this point, then, the project has 40 lines of source code. Where to go from here?&lt;/p&gt;

&lt;h1&gt;Switching view controllers&lt;/h1&gt;

&lt;p&gt;That&amp;#8217;s the main point. When the user selects one of the four choices available in the pop-up button (Image, Table, Video or iSight Camera) the custom view responds by switching to the corresponding view alternative. As regards complexity, meaning breadth and depth of view controller nesting, the requirement is very trivial. Breadth of four, depth of one. It&amp;#8217;s hardly worth having any meta-control. But you have to start somewhere. Here&amp;#8217;s as good a place as any.&lt;/p&gt;

&lt;p&gt;To be continued.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/K1hzRTJyvxA" height="1" width="1"/&gt;</description>
      <pubDate>Fri, 29 Aug 2008 01:37:41 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:87a29f17-ae21-4f69-b92c-d838109e3e48</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2008/08/29/organising-view-controllers#comments</comments>
      <category>AppKit</category>
      <category>view</category>
      <category>controller</category>
      <category>appkit</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=11</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/K1hzRTJyvxA/organising-view-controllers</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2008/08/29/organising-view-controllers</feedburner:origLink></item>
    <item>
      <title>View controllers</title>
      <description>&lt;p&gt;&lt;code&gt;NSViewController&lt;/code&gt;. It&amp;#8217;s an enigmatic class.&lt;/p&gt;

&lt;p&gt;Exactly what is it? When should it be used? Apple&amp;#8217;s documentation does not paint a clear picture. What is there to glean from its interface, implementation as well as others&amp;#8217; work on this subject?&lt;/p&gt;

&lt;h1&gt;Class diagram&lt;/h1&gt;

&lt;p&gt;The class belongs to the &lt;code&gt;AppKit&lt;/code&gt; framework. Its simplified &lt;a href="http://en.wikipedia.org/wiki/Unified_Modeling_Language"&gt;UML&lt;/a&gt; class diagram looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://pioneeringsoftware.s3.amazonaws.com/blog/2008-08-26_view_controller_class_diagram.png" alt="View Controller class diagram" /&gt;&lt;/p&gt;

&lt;p&gt;It inherits from &lt;code&gt;NSResponder&lt;/code&gt;, associates with a bundle, a view and some other represented object. That&amp;#8217;s what the diagram says, in not so many words. Really though, the bundle association amounts to a nib association using a given nib name.&lt;/p&gt;

&lt;h2&gt;Title&lt;/h2&gt;

&lt;p&gt;What does the &lt;code&gt;title&lt;/code&gt; attribute represent? An interesting question. Apple&amp;#8217;s documentation proves most enigmatic. Described as the &amp;#8216;localized title of the receiver&amp;#8217;s view,&amp;#8217; the discussion continues:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&amp;#8220;&lt;code&gt;NSViewController&lt;/code&gt; does not use the title property directly. This property is here because so many anticipated uses of this class will involve letting the user choose among multiple named views using a pulldown menu or some other user interface.&amp;#8221;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Exactly what &amp;#8216;anticipated uses&amp;#8217; refers to, the reader is left to wonder! The warm feeling of anticipation remains.&lt;/p&gt;

&lt;h1&gt;Usage&lt;/h1&gt;

&lt;p&gt;According to documentation, the view controller becomes the nib&amp;#8217;s owner. Its view outlet connects to the nib&amp;#8217;s primary view. Using Interface Builder&amp;#8217;s &lt;em&gt;Cocoa View&lt;/em&gt; template gives you such a nib. The class of &lt;em&gt;File&amp;#8217;s Owner&lt;/em&gt; defaults to &lt;code&gt;NSObject&lt;/code&gt;. Change this to &lt;code&gt;NSViewController&lt;/code&gt; and link its &lt;code&gt;view&lt;/code&gt; outlet to &lt;em&gt;Custom View&lt;/em&gt;&amp;#8212;the &lt;code&gt;NSView&lt;/code&gt; already set-up by the template. (Makes you wonder why the View template does &lt;strong&gt;not&lt;/strong&gt; automatically make the file owner&amp;#8217;s class equal to &lt;code&gt;NSViewController&lt;/code&gt; with its &lt;code&gt;view&lt;/code&gt; outlet pointing at the custom view.) Via the nib&amp;#8217;s owner, the controller, views and controls within the nib can bind to some other key-value coding and observing (KVC and KVO) compliant object for key-path &amp;#8220;representedObject&amp;#8221; applied to the controller, i.e. nib owner.&lt;/p&gt;

&lt;p&gt;Does that make any sense? It assumes some grasp of nib and key-value paradigms.&lt;/p&gt;

&lt;p&gt;In simple terms, &lt;code&gt;NSViewController&lt;/code&gt; ties together a view and a model, the represented object. Isn&amp;#8217;t that exactly what we&amp;#8217;d expect from a controller in &lt;a href="http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaDesignPatterns/chapter_5_section_4.html"&gt;MVC&lt;/a&gt; architecture? Superficially, the class is analogous to &lt;code&gt;NSWindowController&lt;/code&gt;. What window controller does for window and document, view controller does for view and represented object: view and model, plus controller. Window controller has &lt;code&gt;-loadWindow&lt;/code&gt; behaviour for loading the window from its nib. View controller analogously carries the &lt;code&gt;-loadView&lt;/code&gt; method. It almost makes you wonder if the two classes should really be one and the same; or belong to the same super-class, an abstract window-view controller.&lt;/p&gt;

&lt;h2&gt;Exemplars&lt;/h2&gt;

&lt;p&gt;Studying examples is a good way to grasp new concepts. A picture paints a thousand words. Samples are software engineering pictures. Where best to find good paintings? Where better than Apple? Surprisingly though, Apple&amp;#8217;s &lt;a href="http://developer.apple.com/samplecode/"&gt;sample code&lt;/a&gt; contains only a few examples that use &lt;code&gt;NSViewController&lt;/code&gt;. Why is that surprising? Anyway, here they are:
- &lt;a href="http://developer.apple.com/samplecode/CrossEvents/"&gt;CrossEvents&lt;/a&gt; from 2007 subclasses the view controller. It demonstrates sending Carbon events and &lt;code&gt;NSNotification&lt;/code&gt;s between Carbon and Cocoa. View controller&amp;#8217;s usage is not the primary focus. It&amp;#8217;s used just as a tool for loading a nib-based &lt;code&gt;NSView&lt;/code&gt;. Not a complicated example, but helps to show that view controllers have their trivial use.
- &lt;a href="http://developer.apple.com/samplecode/HIView-NSView/"&gt;HIView-NSView&lt;/a&gt;&amp;#8212;same can be said. This sample was &lt;em&gt;upgraded&lt;/em&gt; in May 2007 to use &lt;code&gt;NSViewController&lt;/code&gt;.
- &lt;a href="http://developer.apple.com/samplecode/IconCollection/"&gt;IconCollection&lt;/a&gt;&amp;#8212;same again, not a direct demonstration of &lt;code&gt;NSViewController&lt;/code&gt; usage &lt;em&gt;per se&lt;/em&gt;. &lt;code&gt;NSCollectionView&lt;/code&gt;&amp;#8217;s use as an icon collection viewer is the main purpose. Yet it combines window and view controllers together with bindings.
- &lt;a href="http://developer.apple.com/samplecode/SourceView/"&gt;SourceView&lt;/a&gt; is an interesting sample. Relatively complex, it combines custom view-controller subclasses, as well as custom window controller.
- &lt;a href="http://developer.apple.com/samplecode/ViewController/"&gt;ViewController&lt;/a&gt; directly demonstrates view controlling. It has three custom view controllers, one each for image, table and video viewing. The sample also includes a window controller. So interesting to see how window and view controllers co-ordinate.&lt;/p&gt;

&lt;p&gt;Are there any more? I&amp;#8217;ve made a thorough search but no others at Apple Developer. Third-party developer sources may include examples, of course.&lt;/p&gt;

&lt;p&gt;There is one intriguing fact about the Apple samples: only &lt;a href="http://developer.apple.com/samplecode/ViewController/"&gt;ViewController&lt;/a&gt; uses the represented object and only to store a integer representing the number of subviews present in the view controller&amp;#8217;s view. So not really useful.&lt;/p&gt;

&lt;h1&gt;Responder and responder chain&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;NSViewController&lt;/code&gt; is a kind of &lt;code&gt;NSResponder&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What is a responder anyway? If, like me, you generally ignore things that work right until they break, you&amp;#8217;ll likely know little about the &amp;#8220;responder chain,&amp;#8221; how it works and why; simply because it normally doesn&amp;#8217;t matter. The framework takes care of such details. Why concern yourself?&lt;/p&gt;

&lt;p&gt;In this case, the answer is simple. &lt;code&gt;NSViewController&lt;/code&gt; does not automatically join the responder chain, as does &lt;code&gt;NSWindowController&lt;/code&gt;. If you want your view controllers in the chain, you must put them there yourself.&lt;/p&gt;

&lt;h2&gt;Respond to what and how?&lt;/h2&gt;

&lt;p&gt;The simplified story: responders (subclasses of &lt;code&gt;NSResponder&lt;/code&gt;) link up together in a chain. When event or action messages fire, Apple&amp;#8217;s Application Kit invokes the responders one-by-one until it finds a response. Events and actions correspond to keyboard presses, mouse clicks, scroll wheels, tablet events, menu items, help requests and such. Interactive inputs, by another name. Responders include windows, views and application objects, window and view controllers also.&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s a very simplified version. See Apple&amp;#8217;s &lt;a href="http://developer.apple.com/documentation/Cocoa/Conceptual/EventOverview/Introduction/chapter_1_section_1.html"&gt;Cocoa Event-Handling Guide&lt;/a&gt; for the gross details. Read the section entitled The Responder Chain.&lt;/p&gt;

&lt;p&gt;In reality, the responder chain amounts to just a singly-linked list of &lt;code&gt;NSResponder&lt;/code&gt; objects. Each responder encapsulates a &lt;code&gt;nextResponder&lt;/code&gt; reference to the next responder in the chain, or &lt;code&gt;nil&lt;/code&gt; if none. No next responder indicates the end of the chain. Every &lt;code&gt;NSWindow&lt;/code&gt; has a first responder marking the start of the chain. However, the starting point varies; exact route varies too. Multiple responder chains exist at any one time, and which to choose depends on the type of message, whether or not &lt;code&gt;NSWindowController&lt;/code&gt; is involved, and whether document or non-document architecture applies. So not exactly straightforward!&lt;/p&gt;

&lt;p&gt;In all cases though, first responder is always first. Then comes the view hierarchy followed by the enclosing &lt;code&gt;NSWindow&lt;/code&gt; and its delegate.&lt;/p&gt;

&lt;p&gt;Question arises: where in the chain do view controllers belong? For instance, they could sit between the view hierarchy and its window. Alternatively, behind each view so that the view responds first followed immediately by its view controller. In practise, applications may need custom configurations of responders, possibly even dynamic.&lt;/p&gt;

&lt;p&gt;More on this later.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/Y9glFmuVzME" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 26 Aug 2008 12:30:00 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:52ddadd6-7f1c-4307-a6e3-2a4ca9601021</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2008/08/26/view-controllers#comments</comments>
      <category>AppKit</category>
      <category>view</category>
      <category>controller</category>
      <category>appkit</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=9</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/Y9glFmuVzME/view-controllers</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2008/08/26/view-controllers</feedburner:origLink></item>
    <item>
      <title>Permutation class</title>
      <description>&lt;p&gt;Permutations! I&amp;#8217;ve hit this issue quite a number of times in my life: at university, at work. It&amp;#8217;s not unusual to encounter problems where it&amp;#8217;s very handy to able to iterate all possible permutations of something. And catch is: standard libraries sometimes do not offer any help. The engineer is left to tackle the problem by him- or herself.&lt;/p&gt;

&lt;p&gt;The pragmatic answer typically involves digging in some favourite tome. Something like &lt;a href="http://www.nr.com/"&gt;Numerical Recipes&lt;/a&gt;, or &lt;a href="http://www2.toki.or.id/book/AlgDesignManual/"&gt;The Algorithm Design Manual&lt;/a&gt;. All very handy. And perfect if the implementations match your language and environment requirements. Otherwise you&amp;#8217;re left to wade through the theory, or try to port. To understand or to port? That is the question. If, like me, you find yourself choosing between time pressures and interest, you normally end up porting.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s always handy if someone else has already been through the pain and made the gain for you. Quickly digging around the Internet (roughly translated means Googling) might find what you want. But not always exactly. Cutting a long story short, this article tries to fill the gap between permutations and Objective-C.&lt;/p&gt;

&lt;h1&gt;Already done&lt;/h1&gt;

&lt;p&gt;Ah, but work already done? Check out &lt;a href="http://www.roard.com/docs/cookbook/"&gt;Marko Riedel&lt;/a&gt;&amp;#8217;s GNUstep cookbook. Marko publishes some Objective-C code for a permutation enumerator. See section Counting II: Permutation enumerator.&lt;/p&gt;

&lt;p&gt;I have a problem with it though. It&amp;#8217;s sloppy. Call me a fusspot but I like quality code. Marco&amp;#8217;s work while may be functional bears the hallmarks of cobbling: a done flag, zone-allocated array of &lt;code&gt;int&lt;/code&gt;s, no testing for allocation failure. Do I ask too much? Maybe.&lt;/p&gt;

&lt;p&gt;So not already out there! Until now.&lt;/p&gt;

&lt;h1&gt;Ruby Tuesday&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;m a fan of &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt; (and &lt;a href="http://www.rubyonrails.org/"&gt;Rails&lt;/a&gt;). Ruby equips a useful &lt;a href="http://permutation.rubyforge.org/doc/index.html"&gt;permutation enumerator class&lt;/a&gt; written by &lt;a href="http://rubylution.ping.de/"&gt;Florian Frank&lt;/a&gt;. It has a number of admirable qualities, including simplicity. I like classes with low amounts of internal state. They have fewer bugs in general&amp;#8212;maintenance and comprehension easier. True, it has some more advanced features that most would not require. Still, these can be added later when needs arise.&lt;/p&gt;

&lt;p&gt;Only one strange thing about Florien&amp;#8217;s implementation: the &lt;code&gt;@last&lt;/code&gt; instance variable gets assigned by the initialiser but then ignored. Apart from its getter method, other instance methods re-compute &lt;code&gt;last&lt;/code&gt; by asking for the size factorial. Strange. Never mind, our implementation will fix that oddity.&lt;/p&gt;

&lt;p&gt;So here&amp;#8217;s the mission: develop an Objective-C permutation enumerator class based on Florian&amp;#8217;s Ruby implementation, which is itself based on algorithms presented in Steve Skiena&amp;#8217;s The Algorithm Design Manual! Imitation is the sincerest form of flattery. It gives the outcome a satisfactory pedigree. It&amp;#8217;s also more ideal than most porting source-target pairs since their are many conceptual similarities between Objective-C and Ruby, i.e. grounded in C, aspiring to Smalltalk.&lt;/p&gt;

&lt;p&gt;Another advantage of this approach is that getting to mental grips with the underlying algorithm becomes unnecessary. Lazy bones!&lt;/p&gt;

&lt;h1&gt;Test-driven approach&lt;/h1&gt;

&lt;p&gt;As is good practise, let&amp;#8217;s start with a test. It&amp;#8217;s the &lt;em&gt;agile&lt;/em&gt; way. It will mark the development iterations beginning and end: begin with the test fails, end when it succeeds.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s take a very simple test: permuting an array of 3 elements. Our test wants to know how many alternative permutations exist. For arguments sake, the three elements are letters a, b and c. If we had an enumerator called say &lt;code&gt;RRPermutation&lt;/code&gt; that conforms to the &lt;code&gt;NSEnumerator&lt;/code&gt; protocol, our test would output the permutations using the code below.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;Foundation/Foundation.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;RRFoundation/RRPermutation.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="storage storage_type storage_type_c"&gt;int&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;main&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;int&lt;/span&gt; argc, &lt;span class="storage storage_type storage_type_c"&gt;char&lt;/span&gt; *argv&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[]&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
{
    &lt;span class="support support_class support_class_cocoa"&gt;NSAutoreleasePool&lt;/span&gt; *pool = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSAutoreleasePool&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;alloc&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;init&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    RRPermutation *perm = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;RRPermutation &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;alloc&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;initWithSize&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;3&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;for&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;id&lt;/span&gt; indices in perm&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
    {
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Project the indices into the test string "abc". Objective-C does not
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; have a "project" method, as such. We'll need to do this part by hand.
&lt;/span&gt;        &lt;span class="support support_class support_class_cocoa"&gt;NSString&lt;/span&gt; *s = &lt;span class="string string_quoted string_quoted_double string_quoted_double_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc"&gt;@"&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc"&gt;"&lt;/span&gt;&lt;/span&gt;;
        &lt;span class="keyword keyword_control keyword_control_c"&gt;for&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;id&lt;/span&gt; i in indices&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
        {
            s = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;s &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;stringByAppendingString&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc"&gt;@"&lt;/span&gt;abc&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;substringWithRange&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="support support_function support_function_cocoa"&gt;NSMakeRange&lt;/span&gt;(&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;i &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;unsignedIntegerValue&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
        }
        &lt;span class="support support_function support_function_cocoa"&gt;NSLog&lt;/span&gt;(&lt;span class="string string_quoted string_quoted_double string_quoted_double_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc"&gt;@"&lt;/span&gt;%@&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc"&gt;"&lt;/span&gt;&lt;/span&gt;, s);
    }
    &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;perm &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;release&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;pool &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;drain&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;;
}
&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Note! The test code takes permutation values as &lt;em&gt;indices&lt;/em&gt; not values.&lt;/p&gt;

&lt;p&gt;This is important. It means that permutation enumeration is value-type indifferent. The design and implementation does not want to focus on one particular type of value, e.g. string or number. Rather, enumeration of permutation should be generic.&lt;/p&gt;

&lt;p&gt;Hence, the enumeration outputs indices. You then apply (or project, in Ruby terms) the indices to whatever values you want. That&amp;#8217;s neutral. That&amp;#8217;s good. Otherwise, we&amp;#8217;re looking at duplicate implementations for different types, since Objective-C types do not all have first-class status albeit they may have object wrappers. This approach however answers all requirements, including projecting into non-object sequences such as C arrays or plain C strings.&lt;/p&gt;

&lt;p&gt;Test tool in hand. What next?&lt;/p&gt;

&lt;h1&gt;Interface&lt;/h1&gt;

&lt;p&gt;The preceding test case employs just two interface methods,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the initialiser, &lt;code&gt;initWithSize:&lt;/code&gt; and&lt;/li&gt;
&lt;li&gt;the iteration method, &lt;code&gt;nextObject&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Of course, these aren&amp;#8217;t the only methods necessary. They are only the permuting public interface. Add a designated initialiser, a set of accessors and some internals. Add a splash of instance variables (&lt;code&gt;size&lt;/code&gt; and &lt;code&gt;rank&lt;/code&gt;). This is what you get: listing of &lt;code&gt;RRPermutation.h&lt;/code&gt; below.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;Foundation/Foundation.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;interface&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;RRPermutation&lt;/span&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_entity punctuation_definition_entity_other punctuation_definition_entity_other_inherited-class punctuation_definition_entity_other_inherited-class_objc"&gt;:&lt;/span&gt; &lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc"&gt;NSEnumerator&lt;/span&gt;&lt;span class="meta meta_divider meta_divider_objc"&gt;
&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"&gt;{
    NSUInteger size, rank;
}

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;initWithSize&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;aSize&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;rank&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;aRank&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;initWithSize&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;aSize&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;size&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;rank&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;last&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;setRank&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;newRank&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Rank ranges from 0 to factorial of size, less one, i.e. last. Use
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; setRank:0 to reset a permutation enumerator.
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;nextObject&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Send nextObject repeatedly to get the next array of permutation
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; indices. Answers nil after the last. Note that you cannot reset the
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; enumeration using the enumerator interface, although permutation
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; internals allow it.
&lt;/span&gt;
&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Following methods are generally for internal use and might be considered
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; private. Nevertheless, feel free to access them for testing and debugging or
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; other purposes if you wish. They are query methods, operations without side
&lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; effects on enumerator state. So no pitfalls to avoid.
&lt;/span&gt;
&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSArray&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;unrankIndices&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;m&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;

&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h1&gt;Implementation #1&lt;/h1&gt;

&lt;p&gt;Listing of &lt;code&gt;RRPermutation.m&lt;/code&gt; as follows.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;"&lt;/span&gt;RRPermutation.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;"&lt;/span&gt;RRFactorial.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_implementation meta_implementation_objc"&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;implementation&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_objc"&gt;RRPermutation&lt;/span&gt;
&lt;span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"&gt;
&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; designated initialiser
&lt;/span&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;initWithSize&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;aSize&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;rank&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;aRank&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;{
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;(self = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="variable variable_language variable_language_objc"&gt;super&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;init&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;)
    {
        size = aSize;
        rank = aRank;
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Rank steps by one, starting at zero, ending at RRFactorial(size) - 1;
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; no need to store this value because RRFactorial does all the storing
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; for us in its secret cache.
&lt;/span&gt;    }
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; &lt;span class="variable variable_language variable_language_objc"&gt;self&lt;/span&gt;;
}

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;initWithSize&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;aSize&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;{
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="variable variable_language variable_language_objc"&gt;self&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;initWithSize&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;aSize &lt;span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc"&gt;rank&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
}

&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;Accessors&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;size&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;{
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; size;
}

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;rank&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;{
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; rank;
}

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;last&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;{
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; RRFactorial(size) - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;;
}

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;void&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;setRank&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;newRank&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;{
    rank = newRank;
}

&lt;span class="meta meta_section"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c"&gt;pragma mark&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c"&gt;Enumerator&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;id&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;nextObject&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;{
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; rank &amp;lt; RRFactorial(size) ? &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="variable variable_language variable_language_objc"&gt;self&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;unrankIndices&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;rank++&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt; : &lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;;
}

&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSArray&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;unrankIndices&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;NSUInteger&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;m&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;{
    &lt;span class="support support_class support_class_cocoa"&gt;NSMutableArray&lt;/span&gt; *result = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSMutableArray&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;arrayWithCapacity&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;size&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    NSUInteger i;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;for&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;i = &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;; i &amp;lt; size; i++&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
    {
        &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;result &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;addObject&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSNumber&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;numberWithUnsignedInteger&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    }
    &lt;span class="keyword keyword_control keyword_control_c"&gt;for&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;i = &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;; i &amp;lt; size; i++&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
    {
        NSUInteger f = RRFactorial(i);
        NSUInteger x = m % (f * (i + &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;));
        m -= x;
        x /= f;
        &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;result &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;replaceObjectAtIndex&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;size - i - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt; &lt;span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc"&gt;withObject&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSNumber&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;numberWithUnsignedInteger&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;x&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; At this point, Florian decrements x in preparation for the following
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; comparisons with values from the result array. This assumes that x
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; can be negative however. In our case, it cannot because we implement
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; indices using NSUInteger (unsigned) as is the Foundation framework's
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; wont for array indices. To abviate the decrement, the subsequent test
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; becomes greater-than-or-equal-to instead of greater-than. Problem
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; solved, and simplifies the code too.
&lt;/span&gt;        &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; x -= 1;
&lt;/span&gt;        NSUInteger j;
        &lt;span class="keyword keyword_control keyword_control_c"&gt;for&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;j = size - i; j &amp;lt; size; j++&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
        {
            NSUInteger y = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;result &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;objectAtIndex&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;j&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;unsignedIntegerValue&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
            &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;y &amp;gt;= x&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
            {
                &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;result &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;replaceObjectAtIndex&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;j &lt;span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc"&gt;withObject&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSNumber&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;numberWithUnsignedInteger&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;y + &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
            }
        }
    }
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; result;
}

&lt;/span&gt;&lt;span class="storage storage_type storage_type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc"&gt;@&lt;/span&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The &lt;em&gt;size&lt;/em&gt; attribute describes the size of the permutation required: 3 for permutations of three elements, 7 for seven, etc. During enumeration, the &lt;em&gt;rank&lt;/em&gt; attribute ranges in the integer interval [0, &lt;em&gt;size&lt;/em&gt;! - 1] where &lt;em&gt;size&lt;/em&gt;! refers to the factorial of &lt;em&gt;size&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;Testing&lt;/h1&gt;

&lt;p&gt;Applying the testing tool produces:&lt;/p&gt;

&lt;div class="textmate-source twilight"&gt;
&lt;pre&gt;abc
acb
bac
bca
cab
cba
&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Exactly right!&lt;/p&gt;

&lt;h2&gt;Projecting indices&lt;/h2&gt;

&lt;p&gt;Taking a look again at the test code, the loop for projecting the resulting permutation indices needs simplifying. Does it not? It&amp;#8217;s likely something that will be needed time and again, especially when using permutations. It&amp;#8217;s a loop. Each iteration takes the next index (an &lt;code&gt;NSNumber&lt;/code&gt;) and looks up an object from an array of values. The indexed elements combine to form a new array. Project indices! It needs a new &lt;code&gt;NSArray&lt;/code&gt; method, like this:&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_implementation meta_implementation_objc"&gt;&lt;span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"&gt;&lt;span class="meta meta_function meta_function_objc"&gt;- &lt;span class="meta meta_return-type meta_return-type_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSArray&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;projectIndices&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_argument-type meta_argument-type_objc"&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSArray&lt;/span&gt; *&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;indices&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;{
    &lt;span class="support support_class support_class_cocoa"&gt;NSMutableArray&lt;/span&gt; *result = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSMutableArray&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;arrayWithCapacity&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;indices &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;count&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;for&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSNumber&lt;/span&gt; *i in indices&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
    {
        &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;result &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;addObject&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="variable variable_language variable_language_objc"&gt;self&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;objectAtIndex&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;i &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;unsignedIntegerValue&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    }
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; result;
}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Using this, adding it to an Objective-C category applied to &lt;code&gt;NSArray&lt;/code&gt;, lets the test case simplify to:&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;        &lt;span class="support support_function support_function_cocoa"&gt;NSLog&lt;/span&gt;(&lt;span class="string string_quoted string_quoted_double string_quoted_double_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc"&gt;@"&lt;/span&gt;%@&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;abc &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;projectIndices&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;indices&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;componentsJoinedByString&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc"&gt;@"&lt;/span&gt;,&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;);
&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This replaces the test&amp;#8217;s inner loop. Variable &lt;code&gt;abc&lt;/code&gt; is an &lt;code&gt;NSArray&lt;/code&gt; pointer equal to the array given by &lt;code&gt;[NSArray arrayWithObjects:@"a", @"b", @"c", nil]&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;Niggles&lt;/h1&gt;

&lt;p&gt;Call me fussy again, but there is a notable weakness. The implementation of &lt;code&gt;unrankIndices&lt;/code&gt; uses a mutable array of &lt;code&gt;NSNumber&lt;/code&gt; objects. Yet, the implementation really only requires a small fixed array of &lt;code&gt;NSUInteger&lt;/code&gt;s. It might be more efficient to generate the array of unsigned integers first using a stack-allocated buffer, using &lt;code&gt;alloca&lt;/code&gt;. Then, before returning the result, convert the raw C array of integers to an &lt;code&gt;NSArray&lt;/code&gt; of &lt;code&gt;NSNumber&lt;/code&gt; objects.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s a small difference. But is it worthwhile?&lt;/p&gt;

&lt;h1&gt;Download sources&lt;/h1&gt;

&lt;p&gt;MIT-licensed sources &lt;a href="http://pioneeringsoftware.s3.amazonaws.com/blog/RRPermutation.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/wYE7BJrqw_k" height="1" width="1"/&gt;</description>
      <pubDate>Fri, 22 Aug 2008 02:22:00 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:f1236191-ae55-4f0a-a2cb-499c496bdef3</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2008/08/22/permutation-class#comments</comments>
      <category>Foundation</category>
      <category>permutation</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=8</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/wYE7BJrqw_k/permutation-class</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2008/08/22/permutation-class</feedburner:origLink></item>
    <item>
      <title>Factorial function in Objective-C</title>
      <description>&lt;p&gt;Factorial, denoted by &lt;em&gt;n&lt;/em&gt;! and defined as the product of all positive integers less than or equal to &lt;em&gt;n&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;How to implement such a function in Objective-C? It needs to be fast and, of course, accurate. Needless to say it will have limitations. Factorials very quickly become large. The implementation will use &lt;code&gt;NSUInteger&lt;/code&gt; as the numeric type. This type&amp;#8217;s size depends on architecture, 32 or 64 bit. Hence its ability to carry factorials will vary. Whatever the case, whatever architectural limitations and capabilities, the implementation will reside within them. No other choice!&lt;/p&gt;

&lt;h1&gt;Interface&lt;/h1&gt;

&lt;p&gt;The requirement is purely functional. No class required.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;NSUInteger RRFactorial(NSUInteger n);
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;So very simple. One &lt;code&gt;NSUInteger&lt;/code&gt; in, another out. Factorials deal with positive integers only. Hence &lt;em&gt;U&lt;/em&gt; for unsigned integer.&lt;/p&gt;

&lt;h1&gt;Test case&lt;/h1&gt;

&lt;p&gt;The test case iterates all the integers &lt;code&gt;n&lt;/code&gt; between 0 and 19 inclusive and logs the value of &lt;code&gt;n&lt;/code&gt; and &lt;code&gt;RRFactorial(n)&lt;/code&gt;.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;RRFoundation/RRFactorial.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="storage storage_type storage_type_c"&gt;int&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;main&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;&lt;span class="storage storage_type storage_type_c"&gt;int&lt;/span&gt; argc, &lt;span class="storage storage_type storage_type_c"&gt;char&lt;/span&gt; *argv&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[]&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
{
    &lt;span class="support support_class support_class_cocoa"&gt;NSAutoreleasePool&lt;/span&gt; *pool = &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSAutoreleasePool&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;alloc&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt; &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;init&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    NSUInteger n;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;for&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;n = &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;; n &amp;lt; &lt;span class="constant constant_numeric constant_numeric_c"&gt;20&lt;/span&gt;; n++&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
    {
        &lt;span class="support support_function support_function_cocoa"&gt;NSLog&lt;/span&gt;(&lt;span class="string string_quoted string_quoted_double string_quoted_double_objc"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc"&gt;@"&lt;/span&gt;%lu %lu&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc"&gt;"&lt;/span&gt;&lt;/span&gt;, (&lt;span class="storage storage_type storage_type_c"&gt;unsigned&lt;/span&gt; &lt;span class="storage storage_type storage_type_c"&gt;long&lt;/span&gt;)n, (&lt;span class="storage storage_type storage_type_c"&gt;unsigned&lt;/span&gt; &lt;span class="storage storage_type storage_type_c"&gt;long&lt;/span&gt;)RRFactorial(n));
    }
    &lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;pool &lt;span class="meta meta_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;drain&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;;
}
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;At first, the test &lt;em&gt;fails&lt;/em&gt; successfully! It even fails to link because no implementation for the function currently exists.&lt;/p&gt;

&lt;h1&gt;Implementation&lt;/h1&gt;

&lt;p&gt;General factorial implementation is extremely simple: given &lt;em&gt;n&lt;/em&gt;, just multiply together every integer between 1 and &lt;em&gt;n&lt;/em&gt; inclusive. Nothing difficult there.&lt;/p&gt;

&lt;p&gt;However, the implementation herein will aim for speed by caching the results dynamically. So having already computed the factorial for any given integer, the answer just becomes a look-up transformation; no calculations required. Space is not at issue. Such a look-up implementation will not usually exceed say 20. After that, answers become silly numbers; e.g. 50! approximately equals &lt;code&gt;3*pow(10,64)&lt;/code&gt;. That&amp;#8217;s a pretty big number and bigger even than &lt;code&gt;DBL_MAX&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Design-by-contract principles will set boundaries. Give it high values of &lt;em&gt;n&lt;/em&gt; and don&amp;#8217;t expect sensible answers. That&amp;#8217;s a way of saying &amp;#8216;ignore it!&amp;#8217;&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;"&lt;/span&gt;RRFactorial.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

NSUInteger&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;RRFactorial&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;NSUInteger n&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
{
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Cache the factorials. Use NSZoneMalloc, Realloc and Free for memory management. For initial revisions, ignore memory leaks at application exit.
&lt;/span&gt;    &lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; NSUInteger *factorials = &lt;span class="constant constant_language constant_language_c"&gt;NULL&lt;/span&gt;;
    &lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; NSUInteger numberOfFactorials;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;factorials == &lt;span class="constant constant_language constant_language_c"&gt;NULL&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
    {
        factorials = &lt;span class="support support_function support_function_cocoa"&gt;NSZoneMalloc&lt;/span&gt;(&lt;span class="support support_function support_function_cocoa"&gt;NSDefaultMallocZone&lt;/span&gt;(), &lt;span class="keyword keyword_operator keyword_operator_sizeof keyword_operator_sizeof_c"&gt;sizeof&lt;/span&gt;(NSUInteger));
        factorials&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt; = &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;;
        numberOfFactorials = &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;;
    }
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;n &amp;gt;= numberOfFactorials&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
    {
        NSUInteger *newFactorials = &lt;span class="support support_function support_function_cocoa"&gt;NSZoneRealloc&lt;/span&gt;(&lt;span class="support support_function support_function_cocoa"&gt;NSDefaultMallocZone&lt;/span&gt;(), factorials, (n + &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;) * &lt;span class="keyword keyword_operator keyword_operator_sizeof keyword_operator_sizeof_c"&gt;sizeof&lt;/span&gt;(NSUInteger));
        factorials = newFactorials;
        &lt;span class="keyword keyword_control keyword_control_c"&gt;while&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;numberOfFactorials &amp;lt;= n&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
        {
            factorials&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;numberOfFactorials&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt; = numberOfFactorials * factorials&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;numberOfFactorials - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
            numberOfFactorials++;
        }
    }
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; factorials&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;n&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
}
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h1&gt;Testing&lt;/h1&gt;

&lt;p&gt;Executing the test case produces:&lt;/p&gt;

&lt;div class="textmate-source twilight"&gt;
&lt;pre&gt;0 1
1 1
2 2
3 6
4 24
5 120
6 720
7 5040
8 40320
9 362880
10 3628800
11 39916800
12 479001600
13 1932053504
14 1278945280
15 2004310016
16 2004189184
17 4006445056
18 3396534272
19 109641728&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Compare this to the factorial tableau at &lt;a href="http://en.wikipedia.org/wiki/Factorial"&gt;Wikipedia&lt;/a&gt;. It&amp;#8217;s a match!&lt;/p&gt;

&lt;p&gt;Or is it? Note deviations starting at &lt;em&gt;n&lt;/em&gt;=13. That&amp;#8217;s because &lt;em&gt;13!&lt;/em&gt; exceeds unsigned integer maximum of about 4,000 million on 32-bit platforms.&lt;/p&gt;

&lt;h2&gt;64-bit testing&lt;/h2&gt;

&lt;p&gt;Switching to pure 64-bit, by making architectures (&lt;code&gt;ARCHS&lt;/code&gt;) equal to &lt;code&gt;ppc64&lt;/code&gt; plus &lt;code&gt;x86_64&lt;/code&gt;, and rerunning the test produces a different result.&lt;/p&gt;

&lt;div class="textmate-source twilight"&gt;
&lt;pre&gt;0 1
1 1
2 2
3 6
4 24
5 120
6 720
7 5040
8 40320
9 362880
10 3628800
11 39916800
12 479001600
13 6227020800
14 87178291200
15 1307674368000
16 20922789888000
17 355687428096000
18 6402373705728000
19 121645100408832000&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Much better. Or should I say less limited. Better is just a point of view in this case because even the 64-bit version will eventually find its limitations. Man&amp;#8217;s got to know his limitations! (&amp;#8220;Dirty&amp;#8221; Harry Callahan, Magnum Force, 1973)&lt;/p&gt;

&lt;h1&gt;Failing gracefully&lt;/h1&gt;

&lt;p&gt;At present, nothing gracefully happens when &lt;em&gt;n&lt;/em&gt; and &lt;em&gt;n&lt;/em&gt;! reach limits of the host machine. That&amp;#8217;s not very satisfying. Should it not stop after overflow? Nor is the fact that the function remains insensitive to memory allocation failures a source of satisfaction. Should it throw exceptions? That&amp;#8217;s messy.&lt;/p&gt;

&lt;p&gt;There&amp;#8217;s another approach.&lt;/p&gt;

&lt;p&gt;Since the factorial cache has limited size under normal conditions, why not make the cache static; its size depending on the compiler&amp;#8217;s &lt;code&gt;NSUInteger&lt;/code&gt; width. Once the cache is full, answer &lt;code&gt;NSUIntegerMax&lt;/code&gt; indicating factorial out of integer range. That would solve two problems at the same time; two birds, one stone.&lt;/p&gt;

&lt;p&gt;Compiler manifest constant &lt;code&gt;__LP64__&lt;/code&gt; signals 64-bit architecture. However, there is also a special &lt;code&gt;NS_BUILD_32_LIKE_64&lt;/code&gt; macro for making &lt;code&gt;NSUInteger&lt;/code&gt; 64 bits wide regardless.&lt;/p&gt;

&lt;p&gt;Updated version below. It eliminates dependence on memory allocation and obviates exception handling for allocation failure and boundary overflow. All in one fell swoop. I&amp;#8217;ve also obfuscated variable names to make it more mathematical in nature: &lt;em&gt;i&lt;/em&gt; for the index of the last computed factorial, &lt;em&gt;f&lt;/em&gt; for the factorials, &lt;em&gt;N&lt;/em&gt; for the upper inclusive boundary of &lt;em&gt;n&lt;/em&gt;. Is that bad?&lt;/p&gt;

&lt;p&gt;&lt;img src="http://pioneeringsoftware.s3.amazonaws.com/blog/2008-08-22_factorial_in_64_bits.png" alt="Factorial in 64 bits" /&gt;&lt;/p&gt;

&lt;h2&gt;Listings&lt;/h2&gt;

&lt;h3&gt;&lt;code&gt;RRFactorial.h&lt;/code&gt;&lt;/h3&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_other string_quoted_other_lt-gt string_quoted_other_lt-gt_include string_quoted_other_lt-gt_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;&amp;lt;&lt;/span&gt;Foundation/Foundation.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

NSUInteger RRFactorial(NSUInteger n);
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Answers the factorial of n, or NSUIntegerMax if factorial exceeds
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; NSUInteger type's upper boundary. Uses Foundation framework's NSUInteger
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; type to carry factorials.
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;&lt;code&gt;RRFactorial.m&lt;/code&gt;&lt;/h2&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class="source source_objc"&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c"&gt;import&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c"&gt;"&lt;/span&gt;RRFactorial.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

NSUInteger&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_c"&gt;RRFactorial&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;NSUInteger n&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
{
    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; Use preprocessor macros to determine the maximum value of n computable
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; within the limits prescribed by NSUInteger, whose bit-width depends on
&lt;/span&gt;    &lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; architecture: either 64 or 32 bits.
&lt;/span&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_c"&gt;if&lt;/span&gt; __LP64__ || NS_BUILD_32_LIKE_64&lt;/span&gt;
&lt;span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c"&gt;define&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c"&gt;N&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_c"&gt;20&lt;/span&gt; &lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; 20! = 2,432,902,008,176,640,000
&lt;/span&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_c"&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_preprocessor meta_preprocessor_macro meta_preprocessor_macro_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_define keyword_control_import_define_c"&gt;define&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_preprocessor entity_name_function_preprocessor_c"&gt;N&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_c"&gt;12&lt;/span&gt; &lt;/span&gt;&lt;span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;//&lt;/span&gt; 12! = 479,001,600
&lt;/span&gt;&lt;span class="meta meta_preprocessor meta_preprocessor_c"&gt;#&lt;span class="keyword keyword_control keyword_control_import keyword_control_import_c"&gt;endif&lt;/span&gt;&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt; (n &amp;gt; N) &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; NSUIntegerMax;
    &lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; NSUInteger f&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;N + &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
    &lt;span class="storage storage_modifier storage_modifier_c"&gt;static&lt;/span&gt; NSUInteger i = &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;;
    &lt;span class="keyword keyword_control keyword_control_c"&gt;if&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;i == &lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
    {
        f&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_c"&gt;0&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt; = &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;;
        i = &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;;
    }
    &lt;span class="keyword keyword_control keyword_control_c"&gt;while&lt;/span&gt;&lt;span class="meta meta_function meta_function_c"&gt; &lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;(&lt;/span&gt;i &amp;lt;= n&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c"&gt;)&lt;/span&gt;&lt;/span&gt;
    {
        f&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;i&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt; = i * f&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;i - &lt;span class="constant constant_numeric constant_numeric_c"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
        i++;
    }
    &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt; f&lt;span class="meta meta_bracketed meta_bracketed_objc"&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;[&lt;/span&gt;n&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc"&gt;]&lt;/span&gt;&lt;/span&gt;;
}
&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Download sources&lt;/h2&gt;

&lt;p&gt;You can download the MIT-licensed sources &lt;a href="http://pioneeringsoftware.s3.amazonaws.com/blog/RRFactorial.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/KFGbW3WLh0k" height="1" width="1"/&gt;</description>
      <pubDate>Thu, 21 Aug 2008 04:04:00 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:d0bdd349-0cf1-4ff4-9abd-5bd35ab1dec3</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2008/08/21/factorial-function-in-objective-c#comments</comments>
      <category>Foundation</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=6</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/KFGbW3WLh0k/factorial-function-in-objective-c</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2008/08/21/factorial-function-in-objective-c</feedburner:origLink></item>
  </channel>
</rss>
