<?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>Out Parameters When ARCing</title>
      <description>&lt;p&gt;Be careful when assigning values to out-parameters when Automatic Reference Counting. Ensure that there is no auto-release pool in-between where you assign the parameter and where you use the out-parameter. Easily overlooked when using C blocks, especially when passing blocks to Cocoa APIs which can enclose your handler within an auto-release pool without you realising it.&lt;/p&gt;

&lt;h2&gt;Problem&lt;/h2&gt;

&lt;p&gt;See example below. It represents the kind of situation not-uncommonly found within Cocoa software: a message argument passes an error by reference, a pointer to a pointer. Please note, the example is entirely fictional. The program below does nothing useful, except to demonstrate the principle.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source dawn"&gt;&lt;span class='linenum'&gt;    1&lt;/span&gt; &lt;span class="source source_objc"&gt;&lt;span class="comment comment_block comment_block_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_begin punctuation_definition_comment_begin_c"&gt;/*&lt;/span&gt;
&lt;span class='linenum'&gt;    2&lt;/span&gt;  * Demonstrates EXC_BAD_ACCESS across an auto-release pool boundary.
&lt;span class='linenum'&gt;    3&lt;/span&gt;  &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_end punctuation_definition_comment_end_c"&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class='linenum'&gt;    4&lt;/span&gt; 
&lt;span class='linenum'&gt;    5&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;Foundation/Foundation.h&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c"&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class='linenum'&gt;    6&lt;/span&gt; 
&lt;span class='linenum'&gt;    7&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;Something&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='linenum'&gt;    8&lt;/span&gt; &lt;span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"&gt;
&lt;span class='linenum'&gt;    9&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_begin punctuation_definition_type_begin_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_end punctuation_definition_type_end_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;doWithError&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_begin punctuation_definition_type_begin_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSError&lt;/span&gt; **&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;outError&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
&lt;span class='linenum'&gt;   10&lt;/span&gt; 
&lt;/span&gt;&lt;span class='linenum'&gt;   11&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 class='linenum'&gt;   12&lt;/span&gt; 
&lt;span class='linenum'&gt;   13&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;Something&lt;/span&gt;
&lt;span class='linenum'&gt;   14&lt;/span&gt; &lt;span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"&gt;
&lt;span class='linenum'&gt;   15&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_begin punctuation_definition_type_begin_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_end punctuation_definition_type_end_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;doWithError&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_begin punctuation_definition_type_begin_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSError&lt;/span&gt; **&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;outError&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='linenum'&gt;   16&lt;/span&gt; &lt;span class="meta meta_block meta_block_c"&gt;&lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c"&gt;{&lt;/span&gt;
&lt;span class='linenum'&gt;   17&lt;/span&gt;     @autoreleasepool
&lt;span class='linenum'&gt;   18&lt;/span&gt;     &lt;span class="meta meta_block meta_block_c"&gt;&lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c"&gt;{&lt;/span&gt;
&lt;span class='linenum'&gt;   19&lt;/span&gt;         *outError = &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;NSError&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;errorWithDomain&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;Emergency&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="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc"&gt;code&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;999&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;userInfo&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 class='linenum'&gt;   20&lt;/span&gt;     &lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class='linenum'&gt;   21&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class='linenum'&gt;   22&lt;/span&gt; 
&lt;/span&gt;&lt;span class='linenum'&gt;   23&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 class='linenum'&gt;   24&lt;/span&gt; 
&lt;span class='linenum'&gt;   25&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="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;main&lt;/span&gt;&lt;span class="meta meta_parens meta_parens_c"&gt;(&lt;span class="storage storage_type storage_type_c"&gt;int&lt;/span&gt; argc, &lt;span class="storage storage_modifier storage_modifier_c"&gt;const&lt;/span&gt; &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_begin punctuation_section_scope_begin_objc"&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='linenum'&gt;   26&lt;/span&gt; &lt;span class="meta meta_block meta_block_c"&gt;&lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c"&gt;{&lt;/span&gt;
&lt;span class='linenum'&gt;   27&lt;/span&gt;     @autoreleasepool
&lt;span class='linenum'&gt;   28&lt;/span&gt;     &lt;span class="meta meta_block meta_block_c"&gt;&lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c"&gt;{&lt;/span&gt;
&lt;span class='linenum'&gt;   29&lt;/span&gt;         &lt;span class="support support_class support_class_cocoa"&gt;NSError&lt;/span&gt; *__autoreleasing error = &lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;;
&lt;span class='linenum'&gt;   30&lt;/span&gt; &lt;span class="punctuation punctuation_whitespace punctuation_whitespace_comment punctuation_whitespace_comment_leading punctuation_whitespace_comment_leading_c++"&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 argument type implicitly becomes
&lt;/span&gt;&lt;span class='linenum'&gt;   31&lt;/span&gt; &lt;span class="punctuation punctuation_whitespace punctuation_whitespace_comment punctuation_whitespace_comment_leading punctuation_whitespace_comment_leading_c++"&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='linenum'&gt;   32&lt;/span&gt; &lt;span class="punctuation punctuation_whitespace punctuation_whitespace_comment punctuation_whitespace_comment_leading punctuation_whitespace_comment_leading_c++"&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;  (NSError *__autoreleasing *)
&lt;/span&gt;&lt;span class='linenum'&gt;   33&lt;/span&gt; &lt;span class="punctuation punctuation_whitespace punctuation_whitespace_comment punctuation_whitespace_comment_leading punctuation_whitespace_comment_leading_c++"&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='linenum'&gt;   34&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;Something &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;init&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;doWithError&lt;span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc"&gt;:&lt;/span&gt;&lt;/span&gt;&amp;amp;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 class='linenum'&gt;   35&lt;/span&gt;         
&lt;span class='linenum'&gt;   36&lt;/span&gt; &lt;span class="punctuation punctuation_whitespace punctuation_whitespace_comment punctuation_whitespace_comment_leading punctuation_whitespace_comment_leading_c++"&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, the main thread gives EXC_BAD_ACCESS.
&lt;/span&gt;&lt;span class='linenum'&gt;   37&lt;/span&gt; &lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_cocoa"&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;, error);
&lt;span class='linenum'&gt;   38&lt;/span&gt;     &lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class='linenum'&gt;   39&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 class='linenum'&gt;   40&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class='linenum'&gt;   41&lt;/span&gt; 
&lt;span class='linenum'&gt;   42&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;NSError&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"&gt;(AutomaticReferenceCounting)
&lt;span class='linenum'&gt;   43&lt;/span&gt; 
&lt;/span&gt;&lt;span class='linenum'&gt;   44&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 class='linenum'&gt;   45&lt;/span&gt; 
&lt;span class='linenum'&gt;   46&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;NSError&lt;/span&gt;&lt;span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"&gt;(AutomaticReferenceCounting)
&lt;span class='linenum'&gt;   47&lt;/span&gt; 
&lt;span class='linenum'&gt;   48&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_begin punctuation_definition_type_begin_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_end punctuation_definition_type_end_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;dealloc&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='linenum'&gt;   49&lt;/span&gt; &lt;span class="meta meta_block meta_block_c"&gt;&lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c"&gt;{&lt;/span&gt;
&lt;span class='linenum'&gt;   50&lt;/span&gt; &lt;span class="punctuation punctuation_whitespace punctuation_whitespace_comment punctuation_whitespace_comment_leading punctuation_whitespace_comment_leading_c++"&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; Place a breakpoint here to see when the error deallocates. You will see
&lt;/span&gt;&lt;span class='linenum'&gt;   51&lt;/span&gt; &lt;span class="punctuation punctuation_whitespace punctuation_whitespace_comment punctuation_whitespace_comment_leading punctuation_whitespace_comment_leading_c++"&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; that the error deallocates at the next autorelease pool, naturally.
&lt;/span&gt;&lt;span class='linenum'&gt;   52&lt;/span&gt; &lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_cocoa"&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;dealloc for %@ at %p&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_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_cocoa"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_cocoa"&gt;NSStringFromClass&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;class&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;), self);
&lt;span class='linenum'&gt;   53&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class='linenum'&gt;   54&lt;/span&gt; 
&lt;/span&gt;&lt;span class='linenum'&gt;   55&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;span class='linenum'&gt;   56&lt;/span&gt; &lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Under the &lt;a href="http://clang.llvm.org/docs/AutomaticReferenceCounting.html"&gt;Automatic Reference Counting using the LLVM compiler&lt;/a&gt;, the &lt;code&gt;outError&lt;/code&gt; argument implicitly adds &lt;code&gt;__autoreleasing&lt;/code&gt; to its type. In other words&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;NSError **
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;actually becomes&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;NSError *__autoreleasing *
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See &lt;a href="http://clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership.inference.indirect_parameters"&gt;indirect parameters&lt;/a&gt; for the rationale. This additional implicit qualifier implies that the &lt;code&gt;NSError&lt;/code&gt; pointer exists on the stack frame subject to release by an auto-release pool.&lt;/p&gt;

&lt;p&gt;No problem so far.&lt;/p&gt;

&lt;p&gt;Looking at line 19, you would never &lt;em&gt;deliberately&lt;/em&gt; enclose the out-parameter assignment within an autorelease pool. The situation might arise however inadvertently when you attempt to do the same thing from within a completion handler block sent to one of Apple&amp;#8217;s APIs, e.g. sending a synchronous URL requestor running a block with a Core Data context. The handler block makes the assignment but while unwinding the stack, a hidden auto-release pool deallocates and reclaims the error object leaving its auto-releasing pointer sitting on the enclosing stack frame dangling in space. When you attempt to access the error, you of course see &lt;code&gt;EXC_BAD_ACCESS&lt;/code&gt;; the error has disappeared.&lt;/p&gt;

&lt;p&gt;So look out for that!&lt;/p&gt;

&lt;h2&gt;Solution&lt;/h2&gt;

&lt;p&gt;The solution is relatively straightforward. Temporarily assign the out-parameter&amp;#8217;s value to an automatic (stack frame) variable with &lt;code&gt;__strong&lt;/code&gt; or no qualifier. No qualifier is the same as strong. Then just before returning, assign the out-parameter, e.g.&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-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_begin punctuation_definition_type_begin_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_end punctuation_definition_type_end_objc"&gt;)&lt;/span&gt;&lt;span class="entity entity_name entity_name_function entity_name_function_objc"&gt;doWithError&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_begin punctuation_definition_type_begin_objc"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_cocoa"&gt;NSError&lt;/span&gt; **&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc"&gt;)&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc"&gt;outError&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class="meta meta_block meta_block_c"&gt;&lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c"&gt;{&lt;/span&gt;
    &lt;span class="support support_class support_class_cocoa"&gt;NSError&lt;/span&gt; *error = &lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;;
    @autoreleasepool
    &lt;span class="meta meta_block meta_block_c"&gt;&lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c"&gt;{&lt;/span&gt;
        error = &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;NSError&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;errorWithDomain&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;Emergency&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="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc"&gt;code&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;999&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;userInfo&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 class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c"&gt;}&lt;/span&gt;&lt;/span&gt;
    
&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_comment punctuation_whitespace_comment_leading punctuation_whitespace_comment_leading_c++"&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 autorelease pool did not deallocate the error because the automatic
&lt;/span&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_comment punctuation_whitespace_comment_leading punctuation_whitespace_comment_leading_c++"&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; "error" variable retains a strong reference.
&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;outError &amp;amp;&amp;amp; *outError == &lt;span class="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;)
    &lt;span class="meta meta_block meta_block_c"&gt;&lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c"&gt;{&lt;/span&gt;
        *outError = error;
    &lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c"&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/TYjpe_N9_6U" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 06 Mar 2012 21:51:11 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:15a58e1b-7718-4dff-941e-9ab36ab9a6ce</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2012/03/06/out-parameters-when-arcing#comments</comments>
      <category>Objective-C</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=36</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/TYjpe_N9_6U/out-parameters-when-arcing</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2012/03/06/out-parameters-when-arcing</feedburner:origLink></item>
    <item>
      <title>Reference Is Not a Tree</title>
      <description>&lt;p&gt;&lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt; is an excellent version control system. However, it does not offer much hand-holding. &lt;a href="http://www.youtube.com/watch?v=4XpnKHJAok8"&gt;Linus&lt;/a&gt; expects you to read the documentation and understand what you are doing. How rude! One of Git&amp;#8217;s primary features includes: making you feel less intelligent than you thought you were! It satisfies this feature quite well. This can prove especially true when dealing with submodules.&lt;/p&gt;

&lt;p&gt;Have you ever seen something like this when working with submodules?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;fatal: reference is not a tree: d001e26744dab4b92014a77a4552a535b8fddad8
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(Your &lt;a href="http://book.git-scm.com/1_the_git_object_model.html"&gt;SHA&lt;/a&gt; may vary.) Reference is &lt;strong&gt;not&lt;/strong&gt; a tree?&lt;/p&gt;

&lt;h2&gt;Dangling Commits&lt;/h2&gt;

&lt;p&gt;When you clone a repository (from now on: &lt;em&gt;repo&lt;/em&gt; for short) as submodules within a super-repo, you can initialise and update any submodules recursively using&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git submodule update --init --recursive
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After doing so however, your submodules will &lt;strong&gt;not&lt;/strong&gt; sit on a branch. Verify this using&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git submodule foreach --recursive git branch
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You will notice that all the submodules report &amp;#8220;no branch.&amp;#8221; They all sit on a &amp;#8216;detached head&amp;#8217; corresponding to the commit for the branch you originally added as a submodule. (Following it so far?)&lt;/p&gt;

&lt;p&gt;So here is the problem: commit any changes to the submodules and you commit to a detached head. When you push the submodule to its origin, Git reports &amp;#8220;everything up-to-date&amp;#8221; because it pushes the master by default. &amp;#8220;Everything up-to-date&amp;#8221; refers to the master and &lt;strong&gt;not&lt;/strong&gt; to the detached head. This can easily catch you out, and doubly so if you use a GUI tool where you might not so easily notice the lack of &amp;#8216;pushing noise&amp;#8217; so to speak.&lt;/p&gt;

&lt;h2&gt;Prevention Better Than Cure&lt;/h2&gt;

&lt;p&gt;What to do? When pushing commits within submodules, make sure you move the submodule to a branch, e.g.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git submodule foreach --recursive git checkout master
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;moves all repos to their &lt;code&gt;master&lt;/code&gt; branch for the submodules and sub-submodules recursively. Do this before committing if you can remember.&lt;/p&gt;

&lt;h2&gt;Reattaching Heads&lt;/h2&gt;

&lt;p&gt;If you forget, you can conveniently verify that you have dangling commits by checking out the master branch within your submodule. Git warns you about &amp;#8216;leaving commits behind.&amp;#8217; You can also verify the dangling commit using&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git submodule foreach --recursive git fsck --no-reflog
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which outputs things like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dangling commit d001e26744dab4b92014a77a4552a535b8fddad8
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(Of course, your SHA may vary again.)&lt;/p&gt;

&lt;p&gt;The fix for detached heads temporarily adds a branch, merges it with master and discards the temporary branch. Use the following Git command sequence within your detached head.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git branch detached
git checkout master
git merge detached
git branch -d detached
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can use any name for the &lt;code&gt;detached&lt;/code&gt; branch. Hereafter, you can happily push your formerly orphaned changes.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/6PV9WQvsxvg" height="1" width="1"/&gt;</description>
      <pubDate>Fri, 13 Jan 2012 01:03:00 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:b0445cd6-8099-4fe4-9258-b30c3cda07c6</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2012/01/13/reference-is-not-a-tree#comments</comments>
      <category>Git</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=34</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/6PV9WQvsxvg/reference-is-not-a-tree</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2012/01/13/reference-is-not-a-tree</feedburner:origLink></item>
    <item>
      <title>Developing a project as an OS X framework and iOS static library at the same time</title>
      <description>&lt;p&gt;You want to develop a framework for OS X and iOS at the same time!&lt;/p&gt;

&lt;p&gt;This is not a strange thing since OS X and iOS are substantially similar underneath: a Unix box running Cocoa. With Lion, Apple seem determined to make them even more similar. And why not?&lt;/p&gt;

&lt;p&gt;You want both framework and library to share identical sources so that you do not need to maintain two mostly-similar sets. If there are any differences, you want to limit that only to &lt;em&gt;actual&lt;/em&gt; differences, not just differences in the way they need compiling and linking.&lt;/p&gt;

&lt;p&gt;There is a simple way to do it.&lt;/p&gt;

&lt;p&gt;To explain how, take a simple example.&lt;/p&gt;

&lt;p&gt;The scenario: You want to develop a framework called MyKit. You want this compiling to a Mac OS X framework for use on OS X and as a static library for use on iOS. The final build products will be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MyKit.framework&lt;/code&gt; with the standard framework layout&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libMyKit.a&lt;/code&gt;, a static library with headers:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MyKit.h&lt;/code&gt;, the monolithic public header&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MyKit/MyKitPrivateHeader.h&lt;/code&gt;, one (or ultimately more) private headers&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Developer tools: Xcode 4.2, build 4D139.&lt;/p&gt;

&lt;h2&gt;How to Use This Article&lt;/h2&gt;

&lt;p&gt;I have pushed a Git repository for a &lt;a href="https://github.com/royratcliffe/MyKit"&gt;sample MyKit project at GitHub&lt;/a&gt;. I recommend examining the &lt;a href="https://github.com/royratcliffe/MyKit/commits/master"&gt;commit history&lt;/a&gt; in concert with the steps outlined below. You can see what has changed at each step.&lt;/p&gt;

&lt;p&gt;The short version looks like this, where &lt;strong&gt;MyKit&lt;/strong&gt; stands for your framework-library&amp;#8217;s product name:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Locate the Product Name build setting for target MyKit (the framework target) and change it from &lt;code&gt;$(TARGET_NAME)&lt;/code&gt; to &lt;code&gt;MyKit&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rename the MyKit framework target from MyKit to MyKitFramework. This just renames the target, &lt;em&gt;not&lt;/em&gt; the product since we have disconnected the two; product name no longer depends on target name.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rename MyKitTests target to MyKitFrameworkTests. This time however, do &lt;em&gt;not&lt;/em&gt; rename the Product Name for this target. Let the product name reflect the target name.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delete &lt;code&gt;MyKit.h&lt;/code&gt; and &lt;code&gt;MyKit.m&lt;/code&gt;, the stubs supplied by the Cocoa Framework template—really delete, not just delete references.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add a Cocoa-based Objective-C category file. Category on &lt;code&gt;NSObject&lt;/code&gt;. Save as &lt;code&gt;NSObject+MyKit&lt;/code&gt;. (This is just for testing. You might also just add existing sources to the framework or create new ones, as many as you like.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add implementations along with a little unit testing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change the &lt;code&gt;NSObject+MyKit.h&lt;/code&gt; header&amp;#8217;s target membership for the MyKitFramework target from Project to Private.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a monolithic header. Make it Public. It serves only to import the private headers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose the Cocoa Touch Static Library template for the new target. Include Unit Tests. Call the product name “MyKitLibrary.”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delete the stub object sources: MyKitLibrary.h and MyKitLibrary.m. Not required.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Also delete the test sources, MyKitLibraryTests.h and m. Also not needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change the product name from $(TARGET_NAME) to MyKit for the MyKitLibrary target. Also add &lt;code&gt;NSObject+MyKit.h&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt; to this target. Make the header a Private member.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change &lt;code&gt;___VARIABLE_bundleIdentifierPrefix:bundleIdentifier___&lt;/code&gt; in the bundle identifier for the test bundle to your company name as a reversed DNS string.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add &lt;code&gt;MyKitTests.m&lt;/code&gt; to the MyKitLibraryTests target.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add &lt;code&gt;-all_load&lt;/code&gt; to the Other Linker Flags for the MyKitLibraryTests target. Now the tests run successfully.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add MyKit.h to the public headers for MyKitLibrary target.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change your library target&amp;#8217;s public and private header folder from &lt;code&gt;/usr/local/include&lt;/code&gt;, the default settings, to &lt;code&gt;include&lt;/code&gt; and &lt;code&gt;include/$(PROJECT_NAME)&lt;/code&gt; respectively.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;For the long version of the story, read on.&lt;/p&gt;

&lt;h2&gt;Create an OS X Cocoa Framework&lt;/h2&gt;

&lt;p&gt;This is the starting point. Call the product MyKit, include unit tests, and use version control. Xcode stubs out a basic template with two targets: one for the framework and a bundle for the unit tests.&lt;/p&gt;

&lt;h2&gt;Product Does Not Equal Target&lt;/h2&gt;

&lt;p&gt;This is a key ingredient. We want multiple targets by different names to create products with the &lt;em&gt;same&lt;/em&gt; name, albeit with differing outcomes.&lt;/p&gt;

&lt;p&gt;Start by disconnecting the dependency between the target and product names. By default, the product name &lt;em&gt;is&lt;/em&gt; the target name. Make the product name equal to MyKit so that you can rename the framework to MyKitFramework.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Locate the Product Name build setting for target MyKit (the framework target) and change it from &lt;code&gt;$(TARGET_NAME)&lt;/code&gt; to &lt;code&gt;MyKit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Rename the MyKit framework target from MyKit to MyKitFramework. This just renames the target, &lt;em&gt;not&lt;/em&gt; the product since we have disconnected the two; product name no longer depends on target name.&lt;/p&gt;

&lt;p&gt;You can now rebuild and retest the framework (Command+U shortcut). The project performs both successfully; although the default unit test successfully fails! Check out the framework under Products. You will notice that its name remains MyKit. Control-click and select Show in Finder to see the evidence directly. Framework product name remains unchanged.&lt;/p&gt;

&lt;p&gt;Do the same for the unit test bundle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Rename MyKitTests target to MyKitFrameworkTests. This time however, do &lt;em&gt;not&lt;/em&gt; rename the Product Name for this target. Let the product name reflect the target name.&lt;/p&gt;

&lt;p&gt;Now you have two targets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MyKitFramework&lt;/li&gt;
&lt;li&gt;MyKitFrameworkTests&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;But you have sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MyKit&lt;/li&gt;
&lt;li&gt;MyKitTests&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Public and Private Headers&lt;/h2&gt;

&lt;p&gt;The Cocoa Framework template only gives a stub for a class called MyKit. It derives from &lt;code&gt;NSObject&lt;/code&gt; and does nothing. Make the &lt;code&gt;MyKit.h&lt;/code&gt; header a private header. This will become the monolithic header for importing all private headers.&lt;/p&gt;

&lt;p&gt;For something our framework will do, let us make it extend a standard object class with a category. This is the most awkward kind of library-oriented thing for Objective-C. Mac OS X handles it gracefully, but iOS has a little issue with loading category-only libraries. We will need to add an addition linker option &lt;code&gt;-all_load&lt;/code&gt; later on.&lt;/p&gt;

&lt;p&gt;So, add a new category on NSObject called &lt;code&gt;MyKit&lt;/code&gt; which adds a new method to &lt;code&gt;NSObject&lt;/code&gt; called &lt;code&gt;-stringFromClass&lt;/code&gt;, an instance method which answers the class name as a string for this instance. Not a very useful method; it amounts to &lt;code&gt;NSStringFromClass([self class])&lt;/code&gt;. Also, something very similar already exists, i.e. &lt;code&gt;-className&lt;/code&gt; appears as a scripting extension, category &lt;code&gt;NSObject(NSScriptClassDescription)&lt;/code&gt;. Still, it will serve as a piece of very simple functionality, for the purpose of testing out linking against a category-only library.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Delete &lt;code&gt;MyKit.h&lt;/code&gt; and &lt;code&gt;MyKit.m&lt;/code&gt;, the stubs supplied by the Cocoa Framework template—really delete, not just delete references.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Add a Cocoa-based Objective-C category file. Command+N is the shortcut. Category on &lt;code&gt;NSObject&lt;/code&gt;. Save as &lt;code&gt;NSObject+MyKit&lt;/code&gt;. Xcode provides the &lt;code&gt;h&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt; extensions appropriately for the header and source. Include in the MyKitFramework target, the default selection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt;: Add the implementation along with a little unit testing.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class='linenum'&gt;    1&lt;/span&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-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="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;stringFromClass&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='linenum'&gt;    2&lt;/span&gt; &lt;span class="meta meta_block meta_block_c"&gt;{
&lt;span class='linenum'&gt;    3&lt;/span&gt;     &lt;span class="keyword keyword_control keyword_control_c"&gt;return&lt;/span&gt;&lt;span class="punctuation punctuation_whitespace punctuation_whitespace_support punctuation_whitespace_support_function punctuation_whitespace_support_function_leading punctuation_whitespace_support_function_leading_cocoa"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_cocoa"&gt;NSStringFromClass&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;class&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='linenum'&gt;    4&lt;/span&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;Unit tests:&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;
&lt;pre class="textmate-source"&gt;&lt;span class='linenum'&gt;    1&lt;/span&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-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;testStringFromClass&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='linenum'&gt;    2&lt;/span&gt; &lt;span class="meta meta_block meta_block_c"&gt;{
&lt;span class='linenum'&gt;    3&lt;/span&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;STAssertEqualObjects&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="support support_class support_class_cocoa"&gt;NSObject&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_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;init&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;stringFromClass&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="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;NSObject&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="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;);
&lt;span class='linenum'&gt;    4&lt;/span&gt;     
&lt;span class='linenum'&gt;    5&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; NSString deploys a class clustering architecture. The actual class is an
&lt;/span&gt;&lt;span class='linenum'&gt;    6&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; implementation-specific sub-class or compatible class, depending on what
&lt;/span&gt;&lt;span class='linenum'&gt;    7&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; kind of string, and presumably what version of Cocoa and on what platform
&lt;/span&gt;&lt;span class='linenum'&gt;    8&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; since the exact underlying class might change. Be prepared for test
&lt;/span&gt;&lt;span class='linenum'&gt;    9&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; breakage.
&lt;/span&gt;&lt;span class='linenum'&gt;   10&lt;/span&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;STAssertEqualObjects&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="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_function-call meta_function-call_objc"&gt;&lt;span class="support support_function support_function_any-method support_function_any-method_objc"&gt;stringFromClass&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="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;__NSCFConstantString&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="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;);
&lt;span class='linenum'&gt;   11&lt;/span&gt;     
&lt;span class='linenum'&gt;   12&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 is freaky. You would not expect this to work. But it does; classes
&lt;/span&gt;&lt;span class='linenum'&gt;   13&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; are also objects. Invoking an instance method on a class: it compiles and
&lt;/span&gt;&lt;span class='linenum'&gt;   14&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; runs! You would expect the compiler to baulk, but no.
&lt;/span&gt;&lt;span class='linenum'&gt;   15&lt;/span&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;STAssertEqualObjects&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="support support_class support_class_cocoa"&gt;NSObject&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;stringFromClass&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="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;NSObject&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="constant constant_language constant_language_objc"&gt;nil&lt;/span&gt;);
&lt;span class='linenum'&gt;   16&lt;/span&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 that the first assertion does &lt;em&gt;not&lt;/em&gt; autorelease the &lt;code&gt;NSObject&lt;/code&gt; instance. The project uses &lt;a href="http://developer.apple.com/technologies/ios5/"&gt;Automatic Reference Counting (ARC)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7&lt;/strong&gt;: Change the &lt;code&gt;NSObject+MyKit.h&lt;/code&gt; header&amp;#8217;s target membership for the MyKitFramework target from Project to Private. This will mean that applications using the framework cannot directly import the header. Instead they will import the monolithic header &lt;code&gt;MyKit.h&lt;/code&gt; which will include all the headers for the framework.&lt;/p&gt;

&lt;p&gt;Note that the unit test module still compiles, even though it imports &amp;#8220;NSObject+MyKit.h&amp;#8221; because Xcode resolves this header against the workspace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 8&lt;/strong&gt;: Create monolithic header. Make it Public. It serves only to import the private headers.&lt;/p&gt;

&lt;p&gt;Now the framework is complete. Next the iOS library.&lt;/p&gt;

&lt;h2&gt;Add Static Library Target&lt;/h2&gt;

&lt;p&gt;Add the Cocoa Touch Static Library target for iOS under iOS Framework &amp;amp; Library in Xcode&amp;#8217;s template chooser, giving it the product name as the target name MyKitLibrary but then subsequently renaming the product. This differing initial target name prevents the library template from stomping over the existing framework sources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 9&lt;/strong&gt;: Choose the Cocoa Touch Static Library template for the new target. Include Unit Tests. Call the product name “MyKitLibrary.” This will become the product name, initially, as well as the target name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 10&lt;/strong&gt;: Delete the stub object sources: MyKitLibrary.h and MyKitLibrary.m. Not required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 11&lt;/strong&gt;: Also delete the test sources, MyKitLibraryTests.h and m. Also not needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 12&lt;/strong&gt;: Change the product name from $(TARGET_NAME) to MyKit for the MyKitLibrary target. Also add &lt;code&gt;NSObject+MyKit.h&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt; to this target. Make the header a Private member.&lt;/p&gt;

&lt;p&gt;There is a bug in Xcode 4.2&amp;#8217;s static library template. It writes &lt;code&gt;___VARIABLE_bundleIdentifierPrefix:bundleIdentifier___&lt;/code&gt; in the bundle identifier for the test bundle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 13&lt;/strong&gt;: Change this to your company name as a reversed DNS string.&lt;/p&gt;

&lt;p&gt;However, you cannot yet run the tests, because there are none defined for the MyKitLibrary target.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 14&lt;/strong&gt;: Add &lt;code&gt;MyKitTests.m&lt;/code&gt; to the MyKitLibraryTests target.&lt;/p&gt;

&lt;p&gt;The test fails at run-time because linking against the library does not automatically import categories.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 15&lt;/strong&gt;: Add &lt;code&gt;-all_load&lt;/code&gt; to the Other Linker Flags for the MyKitLibraryTests target. Now the tests run successfully.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 16&lt;/strong&gt;: Add MyKit.h to the public headers for MyKitLibrary target.&lt;/p&gt;

&lt;h2&gt;Header Search Within the Workspace&lt;/h2&gt;

&lt;p&gt;One more thing to do.&lt;/p&gt;

&lt;p&gt;You do &lt;strong&gt;not&lt;/strong&gt; need to add special header search paths for your client application—not even for iOS applications. Thanks to Xcode 4, the build process automatically picks up the headers from their respective build locations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 17&lt;/strong&gt;: To make this searching work though, you need to change your library target&amp;#8217;s public and private header folder from &lt;code&gt;/usr/local/include&lt;/code&gt;, the default settings, to &lt;code&gt;include&lt;/code&gt; and &lt;code&gt;include/$(PROJECT_NAME)&lt;/code&gt; respectively. If you want to be fancy and make them interdependent, make the &lt;em&gt;public&lt;/em&gt; header folder path equal to &lt;code&gt;include&lt;/code&gt; and the &lt;em&gt;private&lt;/em&gt; equal to &lt;code&gt;$(PUBLIC_HEADERS_FOLDER_PATH)/$(PROJECT_NAME)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Why &lt;code&gt;include&lt;/code&gt;? This is because if you build an iOS application with your library as a dependency and a nested project, Xcode builds everything within a single DerivedData folder. When building the application project and all its dependencies, Xcode automatically adds a header search path at &lt;code&gt;include&lt;/code&gt; within this folder. Installing the library headers at this location lets enclosing projects find them easily.&lt;/p&gt;

&lt;p&gt;Note however, you might notice that compiling fails when you attempt to &lt;em&gt;archive&lt;/em&gt;. The archive step does &lt;em&gt;not&lt;/em&gt; automatically search the &lt;code&gt;include&lt;/code&gt; directory. Instead you need to add it manually, using &lt;code&gt;HEADER_SEARCH_PATHS = $(DSTROOT)/include&lt;/code&gt; in your target build settings.&lt;/p&gt;

&lt;h2&gt;Renaming the Schemes&lt;/h2&gt;

&lt;p&gt;You might want to consider renaming the MyKit scheme to MyKitFramework. You then have two schemes: MyKitFramework for the framework and MyKitLibrary for the library. Logical!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/f54mQNNp2fY" height="1" width="1"/&gt;</description>
      <pubDate>Fri, 05 Aug 2011 05:20:00 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:d4eafd9d-93e6-4929-ba25-64ff144eb56d</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2011/08/05/developing-a-project-as-an-os-x-framework-and-ios-static-library-at-the-same-time#comments</comments>
      <category>Xcode</category>
      <category>xcode</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=31</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/f54mQNNp2fY/developing-a-project-as-an-os-x-framework-and-ios-static-library-at-the-same-time</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2011/08/05/developing-a-project-as-an-os-x-framework-and-ios-static-library-at-the-same-time</feedburner:origLink></item>
    <item>
      <title>ASI HTTP Request Library Review</title>
      <description>&lt;p&gt;&lt;a href="http://allseeing-i.com/ASIHTTPRequest/" title="ASIHTTPRequest Documentation - All-Seeing Interactive"&gt;ASI&lt;/a&gt; has a useful class library for wrapping around the CFNetwork framework, the networking Core Foundation framework designed by Apple as a programming interface to lower-level network capabilities of iOS and OS X; CFNetwork framework is available on both platforms.&lt;/p&gt;

&lt;p&gt;But how useful does &lt;a href="http://allseeing-i.com/ASIHTTPRequest/" title="ASIHTTPRequest Documentation - All-Seeing Interactive"&gt;All-Seeing Interactive&lt;/a&gt;’s work prove to be for interacting with &lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer#RESTful_web_services" title="RESTful web services"&gt;RESTful web services&lt;/a&gt;?&lt;/p&gt;

&lt;h2&gt;Pros&lt;/h2&gt;

&lt;p&gt;It works. That&amp;#8217;s a good start. But not the only important thing. The codebase should provide a foundation, something to build on. Therefore working is &lt;em&gt;one&lt;/em&gt; important quality, but it also needs to provide flexible building blocks on which to build higher level functions of different kinds.&lt;/p&gt;

&lt;h3&gt;Useful Features&lt;/h3&gt;

&lt;p&gt;They include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handles connection retries and redirections&lt;/li&gt;
&lt;li&gt;Handles proxies and authentication&lt;/li&gt;
&lt;li&gt;Has data compression and decompression capabilities&lt;/li&gt;
&lt;li&gt;Has useful operation sub-class for interacting with Amazon S3 (simple static storage)&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Extra Dependencies&lt;/h3&gt;

&lt;p&gt;Not too many. Apart from Apple&amp;#8217;s Cocoa umbrella framework, run-time dependencies include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;libz&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxml2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libtidy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;These libraries are part of the standard platform for both iOS and OS X.&lt;/p&gt;

&lt;p&gt;For build-time and testing dependencies adds &lt;a href="http://gabriel.github.com/gh-unit/"&gt;GHUnit&lt;/a&gt; framework.&lt;/p&gt;

&lt;h2&gt;Cons&lt;/h2&gt;

&lt;p&gt;Cons mainly concern implementational issues.&lt;/p&gt;

&lt;h3&gt;Request Is an Operation&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ASIHTTPRequest&lt;/code&gt; is an &lt;em&gt;operation&lt;/em&gt; to process a request, not the request itself. Hence the request has a delegate too. This jars with Foundation framework semantics where requests &lt;em&gt;are&lt;/em&gt; the request objects not behavioural elements which make requests and collect responses. It&amp;#8217;s a English language problem: “request” is a noun and a verb—a source of ambiguity.&lt;/p&gt;

&lt;h3&gt;Class Architecture&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ASIHTTPRequest&lt;/code&gt; class carries an enormous amount of ‘state’ and sub-state, in the form of a whopping 141 instance variables! In addition, there is a considerable amount of &lt;em&gt;static&lt;/em&gt; state: 35 statics.&lt;/p&gt;

&lt;p&gt;In general, this indicates a lack of class-architecture decomposition. Such approaches throw functionality into the one class, making it easy to implement in the short run, but hard to maintain and error prone in the long run. Cross-coupling leads to unexpected and hard-to-debug side effects. You often find that this approach leaves the design with lots of class-scoped methods inappropriately hanging from classes and nested behaviours switching on various internal and typically undocumented states and sub-states.&lt;/p&gt;

&lt;p&gt;This is the case with &lt;code&gt;ASIHTTPRequest&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Threading and Locks&lt;/h3&gt;

&lt;p&gt;The implementation uses old-style threading and locks. Locks have a performance cost, introduce blocking, and scope for race conditions.&lt;/p&gt;

&lt;p&gt;However, as of version 4.0, iOS support blocks and Grand Central Dispatch which makes better use of multi-cored hardware and multi-threading systems, and makes implementing concurrent operations more robust.&lt;/p&gt;

&lt;h3&gt;Other Noteworthy Cons&lt;/h3&gt;

&lt;p&gt;Other notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Uses a cascading tree of request operations. Every request has a main request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Does not delineate public and private methods, e.g. using categories.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Seems to overlap built-in functionality to some extent. iOS and OS X support some functions such as caching, cookies and authentication at some level.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Request operations run in a single background thread.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;The library has some useful functionality, but at mid-2011 needs some additional work. It does not including any kind of routing functionality for RESTful transactions. And at its core lies a heavy-weight HTTP request operation into which the developers have folded most of the available functionality. For ongoing development goals, it would be nice to see some of the class functionality teased apart with less coupling and more flexibility.&lt;/p&gt;

&lt;h3&gt;-sendAsynchronousRequest:queue:completionHandler:&lt;/h3&gt;

&lt;p&gt;As it turns out, much of the requirement for handling URL connections will be appearing in iOS 5.0; this includes queuing asynchronous request operations, which is the primary focus of &lt;a href="http://allseeing-i.com/ASIHTTPRequest/" title="ASIHTTPRequest Documentation - All-Seeing Interactive"&gt;ASI&lt;/a&gt;&amp;#8217;s library. In the new version of the operating system, you can send &lt;code&gt;-[NSURLConnection sendAsynchronousRequest: queue: completionHandler:]&lt;/code&gt; to run an asynchronous URL request in some operation queue. It invokes a completion handler on the main thread when the request completes. Your block receives the NSURLResponse and the data. This new API becomes available in OS X 10.7 Lion and iOS 5.0!&lt;/p&gt;

&lt;p&gt;iOS 5.0 defines the following interface.&lt;/p&gt;

&lt;div class="textmate-source dawn"&gt;

&lt;pre class="textmate-source lazy"&gt;&lt;span class="source source_objc"&gt;&lt;span class="comment comment_block comment_block_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;/*&lt;/span&gt;!
    @category NSURLConnection(NSURLConnectionQueuedLoading)

    The NSURLConnectionQueuedLoading category on NSURLConnection
    provides the interface to perform asynchronous loading of URL
    requests where the results of the request are delivered to a
    block via an NSOperationQueue.

    Note that there is no guarantee of load ordering implied by this
    method.
 &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_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;NSURLConnection&lt;/span&gt; &lt;span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"&gt;(NSURLConnectionQueuedLoading)

&lt;span class="comment comment_block comment_block_c"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c"&gt;/*&lt;/span&gt;!
    @method       sendAsynchronousRequest:queue:completionHandler:

    @abstract 
                  Performs an asynchronous load of the given
                  request. When the request has completed or failed,
                  the block will be executed from the context of the
                  specified NSOperationQueue.

    @discussion
                  This is a convenience routine that allows for
                  asynchronous loading of an url based resource.  If
                  the resource load is successful, the data parameter
                  to the callback will contain the resource data and
                  the error parameter will be nil.  If the resource
                  load fails, the data parameter will be nil and the
                  error will contain information about the failure.

    @param
         request   The request to load. Note that the request is
                   deep-copied as part of the initialization
                   process. Changes made to the request argument after
                   this method returns do not affect the request that
                   is used for the loading process.

    @param 
         queue     An NSOperationQueue upon which    the handler block will
                   be dispatched.

    @param
         handler   A block which receives the results of the resource load.
 &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_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;sendAsynchronousRequest&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;NSURLRequest&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;request&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;queue&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 support_class_cocoa_leopard"&gt;NSOperationQueue&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;queue&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;completionHandler&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;void&lt;/span&gt; (^&lt;span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_objc"&gt;)&lt;/span&gt;&lt;/span&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;NSURLResponse&lt;/span&gt;*, &lt;span class="support support_class support_class_cocoa"&gt;NSData&lt;/span&gt;*, &lt;span class="support support_class support_class_cocoa"&gt;NSError&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;handler&lt;/span&gt;&lt;/span&gt; NS_AVAILABLE&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;10_7, 5_0);
           
@end
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/8lR8T8DEC_w" height="1" width="1"/&gt;</description>
      <pubDate>Thu, 09 Jun 2011 03:19:00 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:634537ac-fb53-4a2c-9d3f-ec7dc62b8aec</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2011/06/09/asi-http-request-library-review#comments</comments>
      <category>Cocoa</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=28</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/8lR8T8DEC_w/asi-http-request-library-review</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2011/06/09/asi-http-request-library-review</feedburner:origLink></item>
    <item>
      <title>CFNetwork Framework, OS X versus iOS</title>
      <description>&lt;p&gt;A question: What are the differences, if any, between CFNetwork framework on iOS and the same framework under OS X?&lt;/p&gt;

&lt;h2&gt;Mac OS X 10.6 (Snow Leopard)&lt;/h2&gt;

&lt;p&gt;The framework in question lives under CoreServices in OS X. Look under &lt;code&gt;/System/Library/Frameworks&lt;/code&gt; on your Macintosh HD, then under &lt;code&gt;CoreServices.framework&lt;/code&gt;, an umbrella framework for the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AE.framework&lt;/li&gt;
&lt;li&gt;CFNetwork.framework, the framework in question&lt;/li&gt;
&lt;li&gt;CarbonCore.framework&lt;/li&gt;
&lt;li&gt;DictionaryServices.framework&lt;/li&gt;
&lt;li&gt;LaunchServices.framework&lt;/li&gt;
&lt;li&gt;Metadata.framework&lt;/li&gt;
&lt;li&gt;OSServices.framework&lt;/li&gt;
&lt;li&gt;SearchKit.framework&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;iOS 4.3&lt;/h2&gt;

&lt;p&gt;Assuming you have Xcode installed with the necessary iOS platform, you will find CFNetwork.framework in a different place, under the platform SDK&amp;#8217;s system library frameworks at &lt;code&gt;/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk&lt;/code&gt; then under sub-folder &lt;code&gt;System/Library/Frameworks&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;Comparison&lt;/h1&gt;

&lt;p&gt;Note, you cannot compare the frameworks directly. Frameworks on OS X and iOS have differing layouts. On iOS, frameworks lay out in a much simpler way compared to their OS X counterparts. Also, you cannot compare the binary files. The two different platforms, Intel versus ARM, make machine-code comparisons even more meaningless.&lt;/p&gt;

&lt;p&gt;So compare just the framework &lt;code&gt;Headers&lt;/code&gt; sub-folder using the following shell command.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ opendiff /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CFNetwork.framework/Versions/A/Headers /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/CFNetwork.framework/Headers
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note, &lt;code&gt;opendiff&lt;/code&gt; is a command-line front-end to Apple&amp;#8217;s FileMerge tool, a graphical ‘diff!’&lt;/p&gt;

&lt;h1&gt;Results&lt;/h1&gt;

&lt;p&gt;Only three headers of twelve differ.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CFHTTPMessage.h&lt;/code&gt;, 4 differences&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CFProxySupport.h&lt;/code&gt;, 5 differences&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CFSocketStream.h&lt;/code&gt;, 1 difference&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;iOS New Features&lt;/h2&gt;

&lt;p&gt;The details are slightly surprising. In short, iOS has extra features. Perhaps you might assume the reverse. But no.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Negotiate v2 and Kerberos Authentication in iOS 3.0&lt;/p&gt;

&lt;p&gt;iOS 3.0 adds support for HTTP Negotiate v2 and Kerberos authentication schemes. The iOS header promises that this will appear in Lion, OS X 10.7. It carries an &lt;code&gt;__OSX_AVAILABLE_STARTING&lt;/code&gt; macro to that effect.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Proxy PAC JavaScripts in iOS 3.0&lt;/p&gt;

&lt;p&gt;Provides access to the full JavaScript source of a proxy&amp;#8217;s PAC script.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stream Service Types in iOS 4.0&lt;/p&gt;

&lt;p&gt;Supports VoIP.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h1&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;There is no significant difference between CFNetwork.framework headers on iOS and OS X. Therefore, logically, no significant difference between functionality even if the implementation details differ somewhat. Main conclusion: Develop against one, and you develop against the other at the same time.&lt;/p&gt;

&lt;p&gt;As an aside, it appears as though they are two snapshots of the same code base—as you might expect because the two platforms are merging!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/PioneeringSoftware/~4/-Qg512xeezg" height="1" width="1"/&gt;</description>
      <pubDate>Mon, 06 Jun 2011 23:18:00 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:d185f960-3a70-494a-923e-77096a624251</guid>
      <comments>http://blog.pioneeringsoftware.co.uk/2011/06/06/cfnetwork-framework-os-x-versus-ios#comments</comments>
      <category>Cocoa</category>
      <trackback:ping>http://blog.pioneeringsoftware.co.uk/trackbacks?article_id=26</trackback:ping>
      <link>http://feedproxy.google.com/~r/PioneeringSoftware/~3/-Qg512xeezg/cfnetwork-framework-os-x-versus-ios</link>
    <feedburner:origLink>http://blog.pioneeringsoftware.co.uk/2011/06/06/cfnetwork-framework-os-x-versus-ios</feedburner:origLink></item>
    <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>
  </channel>
</rss>

