numist the fool 2015-08-03T10:12:15-07:00 http://numist.net/ © 2009 - 2024, Scott Perry Composing Stick test multiplication via subclassing tag:numist.net,2012-04-03:../post/2015/test-multiplication-via-subclassing.html 2015-08-03T10:12:15-07:00 2015-08-03T10:12:15-07:00 Scott Perry http://numist.net/ spam@numist.net <p style="color:#999"><b>Note:</b> This blog post may contain video or JavaScript effects that are illegal in feeds and will be removed by most readers/aggregators. Some styling may also be lost, but it should display perfectly if you <a style="color:#999" href="../post/2015/test-multiplication-via-subclassing.html">open it in your browser</a>.</p> <p>Let's say I'm writing an RSS reader. (With apologies to <a href="http://inessential.com/2015/07/19/secret_projects_diary_2_swift_2_0_prot">Brent Simmons</a>.)</p> <p>And let's say that it will support a number of different services. In order to make it easier to write different implementations for each service, I might write <tt>Feed</tt> and <tt>Folder</tt> protocols to allow them to share a common interface. The <tt>Folder</tt> protocol might look something like:</p> <p><pre class="textmate-source mac_classic"><span class="source source_objc"><span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>protocol</span> <span class="entity entity_name entity_name_type entity_name_type_objc">Folder</span> <span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>NSObject<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span> <span class="meta meta_property-with-attributes meta_property-with-attributes_objc"><span class="keyword keyword_other keyword_other_property keyword_other_property_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>property</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">(</span><span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">readonly</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">strong</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">)</span></span> <span class="support support_class support_class_cocoa support_class_cocoa_objc">NSArray</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>id&lt;Feed<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span>> *feeds; <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">addFeeds</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa support_class_cocoa_objc">NSArray</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>id&lt;Feed<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span>> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">feeds</span></span>;</span> <span class="comment comment_block comment_block_c"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_begin punctuation_definition_comment_begin_c">/*</span> … <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_end punctuation_definition_comment_end_c">*/</span></span> </span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span> </span></pre></p> <p>With this protocol, I can implement concrete classes for each service, such as <tt>LocalFolder</tt>, <tt>FeedBinFolder</tt>, <tt>FeedlyFolder</tt>, etc.</p> <p>But how do I test them?</p> <p>Being <tt>Folder</tt>-compliant, all instances of these classes must maintain a common set of guarantees. For example, adding feeds with <tt>addFeeds:</tt> should cause those feeds to be accessible via the <tt>feeds</tt> property of the folder. That test could look like:</p> <p><pre class="textmate-source mac_classic"><span class="source source_objc"><span class="meta meta_implementation meta_implementation_objc"><span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"><span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">testAddFeed</span></span> </span><span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="meta meta_id-with-protocol meta_id-with-protocol_objc"><span class="storage storage_type storage_type_objc">id</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>Folder<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span></span> testFolder = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="variable variable_language variable_language_objc">self</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">folder</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="meta meta_id-with-protocol meta_id-with-protocol_objc"><span class="storage storage_type storage_type_objc">id</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>Feed<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span></span> testFeed = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="variable variable_language variable_language_objc">self</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">feed</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>testFolder <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">addFeeds<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>@<span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>testFeed<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">XCTAssert</span>(</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>testFolder.feeds <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">containsObject<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>testFeed</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>); <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> </span></span></span></pre></p> <p>I'd like to run this test against all the different types that conform to <tt>Folder</tt>, and this is made possible by test subclassing.</p> <p>Here's a test superclass, filled with the tests I'd like to run on all my <tt>Folder</tt>-compliant types, configured by default to test <tt>LocalFolder</tt>:</p> <p><pre class="textmate-source mac_classic"><span class="source source_objc"><span class="meta meta_implementation meta_implementation_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>implementation</span> <span class="entity entity_name entity_name_type entity_name_type_objc">FolderTests</span> <span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="meta meta_id-with-protocol meta_id-with-protocol_objc"><span class="storage storage_type storage_type_objc">id</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>Folder<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">folder</span></span> </span><span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="keyword keyword_control keyword_control_c">return</span> <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>LocalFolder <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">new</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="meta meta_id-with-protocol meta_id-with-protocol_objc"><span class="storage storage_type storage_type_objc">id</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>Feed<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">feed</span></span> </span><span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="keyword keyword_control keyword_control_c">return</span> <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>LocalFeed <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">new</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">testAddFeed</span></span> </span><span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="meta meta_id-with-protocol meta_id-with-protocol_objc"><span class="storage storage_type storage_type_objc">id</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>Folder<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span></span> testFolder = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="variable variable_language variable_language_objc">self</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">folder</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="meta meta_id-with-protocol meta_id-with-protocol_objc"><span class="storage storage_type storage_type_objc">id</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>Feed<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span></span> testFeed = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="variable variable_language variable_language_objc">self</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">feed</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>testFolder <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">addFeeds<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>@<span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>testFeed<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">XCTAssert</span>(</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>testFolder.feeds <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">containsObject<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>testFeed</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>); <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">testAddThousandsOfFeeds</span></span> </span><span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="variable variable_language variable_language_objc">self</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">measureBlock<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>^<span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="comment comment_block comment_block_c"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_begin punctuation_definition_comment_begin_c">/*</span> … <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_end punctuation_definition_comment_end_c">*/</span></span> <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> </span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span></span></pre></p> <p>The interface describes the methods that subclasses should overload:</p> <p><pre class="textmate-source mac_classic"><span class="source source_objc"><span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>interface</span> <span class="entity entity_name entity_name_type entity_name_type_objc">FolderTests</span> <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">:</span> <span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc">XCTestCase</span><span class="meta meta_divider meta_divider_objc"> </span><span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="meta meta_id-with-protocol meta_id-with-protocol_objc"><span class="storage storage_type storage_type_objc">id</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>Folder<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">folder</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="meta meta_id-with-protocol meta_id-with-protocol_objc"><span class="storage storage_type storage_type_objc">id</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>Feed<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">feed</span></span>;</span> </span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span></span></pre></p> <p>To test the other <tt>Folder</tt>-compliant types, I implement subclasses of <tt>FolderTests</tt> like this one, for <tt>FeedBinFolder</tt>:</p> <p><pre class="textmate-source mac_classic"><span class="source source_objc"><span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>interface</span> <span class="entity entity_name entity_name_type entity_name_type_objc">FeedBinFolderTests</span> <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">:</span> <span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc">FolderTests</span><span class="meta meta_divider meta_divider_objc"> </span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span> <span class="meta meta_implementation meta_implementation_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>implementation</span> <span class="entity entity_name entity_name_type entity_name_type_objc">FeedBinFolderTests</span> <span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="meta meta_id-with-protocol meta_id-with-protocol_objc"><span class="storage storage_type storage_type_objc">id</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>Folder<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">folder</span></span> </span><span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="keyword keyword_control keyword_control_c">return</span> <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>FeedBinFolder <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">new</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="meta meta_id-with-protocol meta_id-with-protocol_objc"><span class="storage storage_type storage_type_objc">id</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>Feed<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">feed</span></span> </span><span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="keyword keyword_control keyword_control_c">return</span> <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>FeedBinFeed <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">new</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">testFeedBinSpecific</span></span> </span><span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="comment comment_block comment_block_c"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_begin punctuation_definition_comment_begin_c">/*</span> … <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_end punctuation_definition_comment_end_c">*/</span></span> <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> </span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span></span></pre></p> <p>At this point, I've written a total of three test methods. Running the test target, the console shows:</p> <p><pre class="textmate-source mac_classic">Test Suite 'All tests' started at 2015-07-31 11:30:55.855 Test Suite 'FolderTests.xctest' started at 2015-07-31 11:30:55.857 Test Suite 'FeedBinFolderTests' started at 2015-07-31 11:30:55.857 Test Case '-[FeedBinFolderTests testAddFeed]' started. Test Case '-[FeedBinFolderTests testAddFeed]' passed (0.000 seconds). Test Case '-[FeedBinFolderTests testAddThousandsOfFeeds]' started. Test Case '-[FeedBinFolderTests testAddThousandsOfFeeds]' measured [Time, seconds] &lt;…snip…&gt; Test Case '-[FeedBinFolderTests testAddThousandsOfFeeds]' passed (0.492 seconds). Test Case '-[FeedBinFolderTests testFeedBinSpecific]' started. Test Case '-[FeedBinFolderTests testFeedBinSpecific]' passed (0.000 seconds). Test Suite 'FeedBinFolderTests' passed at 2015-07-31 11:30:56.351. Executed 3 tests, with 0 failures (0 unexpected) in 0.492 (0.494) seconds Test Suite 'FolderTests' started at 2015-07-31 11:30:56.351 Test Case '-[FolderTests testAddFeed]' started. Test Case '-[FolderTests testAddFeed]' passed (0.000 seconds). Test Case '-[FolderTests testAddThousandsOfFeeds]' started. Test Case '-[FolderTests testAddThousandsOfFeeds]' measured [Time, seconds] &lt;…snip…&gt; Test Case '-[FolderTests testAddThousandsOfFeeds]' passed (0.259 seconds). Test Suite 'FolderTests' passed at 2015-07-31 11:30:56.611. Executed 2 tests, with 0 failures (0 unexpected) in 0.259 (0.260) seconds Test Suite 'FolderTests.xctest' passed at 2015-07-31 11:30:56.611. Executed 5 tests, with 0 failures (0 unexpected) in 0.752 (0.755) seconds Test Suite 'All tests' passed at 2015-07-31 11:30:56.612. Executed 5 tests, with 0 failures (0 unexpected) in 0.752 (0.757) seconds </pre></p> <p>I wrote three test methods, but XCTest ran five tests. If I wrote the most basic <tt>FolderTests</tt> subclass possible for <tt>FeedlyFolder</tt>, the effective test count would go from five to seven. If I then added a <tt>testRemoveFeeds</tt> test to <tt>FolderTests</tt>, it would be inherited by the test subclasses as well, raising the count further to ten.</p> <p>This approach takes advantage of a powerful yet little known feature of XCTest; creating a test case subclass causes that class to inherit and run all of its ancestors' tests. This is really useful pattern for testing functional protocol conformances, such as our working example, or high level black box testing for classes that support configuration, like a database engine or compiler.</p> <div class="footnotes"><hr> The example code behind the snippets in this post can be found <a href="../../../data/2015/test-multiplication-via-subclassing/FolderTests.m">here</a>. </div> do it for the love tag:numist.net,2012-04-03:../post/2014/do-it-for-the-love.html 2014-09-11T10:23:21-07:00 2014-09-11T10:23:21-07:00 Scott Perry http://numist.net/ spam@numist.net <div class="defs" style="margin: 3em; margin-top: 2em;"> <span class="Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-family: Times; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><!-- wordid: 2115--></span> <div class="def" style="margin-top: 1em;"> <span class="Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-family: Times; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><span class="def" style="font-family: Baskerville;"><span class="hwGrp" d:priority="2" style="font-weight: normal;"><span class="hw" d:priority="2" d:dhw="1" style="font-size: 24px;">am <span class="hsb" style="font-size: 75%;">•</span> a <span class="hsb" style="font-size: 75%;">•</span> teur</span> </span> <span class="SB" style="display: block; margin-left: 1em; text-indent: -1em;"><span class="prelim"><span class="ps" d:ps="1" style="font-weight: normal;">noun</span></span></span> <span class="etymBlock" d:priority="2" style="display: block; margin-top: 1em; text-indent: 0px;"><span class="lbl" style="font-size: 14px;">ORIGIN</span> <span class="date" style="font-weight: normal;">late 18<sup>th</sup> cent.</span> : from <span class="lang" style="font-weight: normal;">French</span> , from <span class="lang" style="font-weight: normal;">Italian</span> <span class="ff" style="font-weight: 600; font-style: italic;">amatore</span> , from <span class="lang" style="font-weight: normal;">Latin</span> <span class="ff" style="font-weight: 600; font-style: italic;">amator</span> <span class="trans" style="font-weight: 600; font-style: italic;">‘lover,’</span> from <span class="ff" style="font-weight: 600; font-style: italic;">amare</span> <span class="trans" style="font-weight: 600; font-style: italic;">‘to love.’</span></span></span></span> </div> </div> traits tag:numist.net,2012-04-03:../post/2014/traits.html 2014-05-16T13:34:43-07:00 2014-05-16T13:34:43-07:00 Scott Perry http://numist.net/ spam@numist.net <p style="color:#999"><b>Note:</b> This blog post may contain video or JavaScript effects that are illegal in feeds and will be removed by most readers/aggregators. Some styling may also be lost, but it should display perfectly if you <a style="color:#999" href="../post/2014/traits.html">open it in your browser</a>.</p> <h2>concrete protocols</h2> <p>I didn't know the term "concrete protocol" until fairly recently, but it was pretty easy to understand: a concrete protocol comes with default implementations for some of its methods. Foundation already flirts with the idea of concrete protocols with its collections' subclassing strategies—if you want to build your own array, you only have to implement <tt>-count</tt> and <tt>-objectAtIndex:</tt> in your <tt>NSArray</tt> subclass in order to support all of the other instance methods provided by the class. Written as a concrete protocol, it might look something like this:</p> <p><pre class="textmate-source mac_classic"><span class="source source_objc"><span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>protocol</span> <span class="entity entity_name entity_name_type entity_name_type_objc">NSArray</span> <span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span><span class="support support_other support_other_protocol support_other_protocol_objc">NSCopying</span>, <span class="support support_other support_other_protocol support_other_protocol_objc">NSMutableCopying</span>, NSSecureCoding, NSFastEnumeration<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span> <span class="keyword keyword_control keyword_control_protocol-specification keyword_control_protocol-specification_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>required</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa support_type_cocoa_leopard">NSUInteger</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">count</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">objectAtIndex</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa support_type_cocoa_leopard">NSUInteger</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">index</span></span>;</span> <span class="keyword keyword_control keyword_control_protocol-specification keyword_control_protocol-specification_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>provided</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSString</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">componentsJoinedByString</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSString</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">separator</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_objc">BOOL</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">containsObject</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">anObject</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSString</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">description</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSString</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">descriptionWithLocale</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">locale</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSString</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">descriptionWithLocale</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">locale</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">indent</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa support_type_cocoa_leopard">NSUInteger</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">level</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">firstObjectCommonWithArray</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSArray</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">otherArray</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">getObjects</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span> __unsafe_unretained <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">objects</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">range</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa">NSRange</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">range</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa support_type_cocoa_leopard">NSUInteger</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">indexOfObject</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">anObject</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa support_type_cocoa_leopard">NSUInteger</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">indexOfObject</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">anObject</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">inRange</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa">NSRange</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">range</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa support_type_cocoa_leopard">NSUInteger</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">indexOfObjectIdenticalTo</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">anObject</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa support_type_cocoa_leopard">NSUInteger</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">indexOfObjectIdenticalTo</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">anObject</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">inRange</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa">NSRange</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">range</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_objc">BOOL</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">isEqualToArray</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSArray</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">otherArray</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">firstObject</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">lastObject</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSEnumerator</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">objectEnumerator</span></span>;</span> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSEnumerator</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">reverseObjectEnumerator</span></span>;</span> <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c++">//</span> two dozen more methods…</span></span></span></span></pre></p> <!-- more --> <p>Compared to subclassing, a concrete protocol lacks state of its own, but allows for multiple inheritence. To make the effects of this more obvious, let's look at a class that would obviously benefit from multiple inheritence: <tt>NSOrderedSet</tt>.</p> <p>Today's <tt>NSOrderedSet</tt> is (almost) API-compatible with both <tt>NSArray</tt> and <tt>NSSet</tt>. It supports the fast membership testing and single-instance-storage semantics of sets, while also providing array-like indexing and iteration. It's perfect for things like <a href="https://github.com/numist/Switch/">Switch</a>'s window list interface. Yet <tt>NSOrderedSet</tt> inherits from <tt>NSObject</tt>.</p> <p>In a world with concrete protocols, the declaration of <tt>NSOrderedSet</tt> would look like this:</p> <p><pre class="textmate-source mac_classic"><span class="source source_objc"><span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>interface</span> <span class="entity entity_name entity_name_type entity_name_type_objc">NSOrderedSet</span> <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">:</span> <span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc">NSObject</span><span class="meta meta_divider meta_divider_objc"> </span><span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>NSArray, NSSet<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">></span></span> </span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span></span></pre></p> <p>Unfortunately, this example also reveals a flaw in concrete protocols as tools for composition: conflicts. Among other methods, both protocols provide <tt>-containsObject:</tt>. There are a number of solutions to this problem, including using the protocol ordering in the class declaration for precedence, or assigning efficiency factors to the implementation of each provided method to be resolved when the class is registered with the runtime.</p> <p>Luckily, there's a better way.</p> <h2>traits</h2> <p>The <a href="http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf">paper on traits</a>—which is super readable and not very long—was published in 2003; it provides a solution for conflict resolution and also explores how traits compare to multiple inheritance, single inheritence, and mixins. The conflict resolution is pretty simple: conflicting method implementations in inherited traits get aliased and the method becomes required. Classes resolve the conflicts by implementing the method and either forwarding the call to one of the aliased methods or providing their own implementation. The net of this for something like ordered sets is that <a href="https://github.com/numist/Traitor/blob/master/Example/ADMutableOrderedSet.m">an ordered set for Objective-C can be written in less than 150 lines</a>, a third of which are conflict resolution.</p> <p>Traits—like protocols—can inherit from other traits, so the <tt>NSArray</tt> and <tt>NSSet</tt> traits could inherit from <tt>NSFastEnumeration</tt>, which could inherit from <tt>NSEnumerable</tt>, which could provide map, reduce, and filter. This represents a case of the <a href="http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem">diamond problem</a> that is trivially resolved with traits because of the absence of state; the methods are the same, so the conflicts that would arise from their need for state are managed at the level of the required state accessors.</p> <p>This makes traits really powerful for building tools. Want a <a href="https://github.com/numist/Traitor/blob/master/Example/ADPriorityQueue.m">priority queue</a> that supports all of the methods of an immutable array? 80 lines of code. Future possibilities for traits that aren't elucidated in the paper are also really exciting—what if you could write a category for the <tt>NSSet</tt> trait that returned a new set representing the union, minus, or intersection with another set<sup><a href="#2014/traits/fn1">1</a></sup>? You'd be extending not only <tt>NSSet</tt>, but also any type that wants set-like behaviour.</p> <h2>learning by doing</h2> <p>In order to explore the effects of traits, I wrote <a href="https://github.com/numist/Traitor">Traitor</a>. It is a basic implementation for Objective-C that performs all of the safety checks that traits support as early as possible in the execution of the application<sup><a href="#2014/traits/fn2">2</a></sup>. This means that classes that are dynamically registered with the runtime can't use traits, but otherwise there should be no problems at runtime due to problems with traits. Reinventing arrays and sets was annoying, but the power of being able to leverage them both in new classes was eye-opening, especially when all the collection classes gained list comprehension methods just from adding a single trait to the hierarchy.</p> <div class="footnotes"><hr /> <a name="2014/traits/fn1"></a><sup>1</sup> <tt>NSMutableSet</tt> implements set operations already, but they are destructive. Why doesn't <tt>NSSet</tt> implement set operations, anyway?<br /> <a name="2014/traits/fn2"></a><sup>2</sup> Trait correctness can be statically checked, but Only Apple Can Do This™.<br /> </div> a new kind of timer tag:numist.net,2012-04-03:../post/2014/a-new-kind-of-timer.html 2014-04-22T12:24:01-07:00 2014-04-22T12:24:01-07:00 Scott Perry http://numist.net/ spam@numist.net <p style="color:#999"><b>Note:</b> This blog post may contain video or JavaScript effects that are illegal in feeds and will be removed by most readers/aggregators. Some styling may also be lost, but it should display perfectly if you <a style="color:#999" href="../post/2014/a-new-kind-of-timer.html">open it in your browser</a>.</p> <p>Subscriptions and locks commonly come with APIs that require balanced calls, but they represent a subclass of a larger pattern of managing resources that must be freed. In the case of global notifications, the observer causes system resources to be allocated for notification dispatch, and that all needs to be cleaned up when the observer is no longer interested.</p> <p>Another pattern of resource allocation is when dealing with file descriptors, which are easy to forget to close in sufficiently complicated codebases. A solution to this problem is an idiom known as <a href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization">Resource Acquisition Is Initialization</a>, which <tt>NSFileHandle</tt> implements<sup><a href="#2014/a-new-kind-of-timer/fn1">1</a></sup>. There are still some areas where this paradigm isn't present in Apple's APIs, such as <tt>NSDocument</tt> and <tt>NSMachPort</tt>, but today we're going to look at <tt>NSTimer</tt>.</p> <!-- more --> <p>From the perspective of RAII, <tt>NSTimer</tt> is a disaster. Instead of maintaining an unsafe reference to its target like <tt>NSNotificationCenter</tt>, an instance of <tt>NSTimer</tt> retains its target until it's invalidated. Furthermore, the timer itself is retained by the run loop to which it is registered. Since a reference to the timer must be maintained in order to manually invalidate it, the resulting object graph is strong back references plus a retain cycle:</p> <p><img src="../data/2014/a-new-kind-of-timer/NSTimer.png" width="328" height="59"></p> <p>Since <tt>NSTimer</tt> is responsible for allocating scheduler resources on behalf of its target, and anything involving the run loop should be an implementation detail of the timer itself, the object graph from the perspective of the client <em>should</em> look like this:</p> <p><img src="../data/2014/a-new-kind-of-timer/NNTimer.png" width="203" height="59"></p> <p>We could solve this problem with a proxy that stands in for the target to avoid the reference cycle, plus another proxy that stands in for the timer and invalidates it in the pattern of <tt><a href="https://github.com/numist/NNKit/blob/master/NNKit/Actors/NNSelfInvalidatingObject.h">NNSelfInvalidatingObject</a></tt>. The resulting relationship graph would look like:</p> <p><img src="../data/2014/a-new-kind-of-timer/NSRubeGoldbergTimer.png" width="635" height="89"></p> <p>This still sucks, and doesn't change the fact that <tt>NSTimer</tt> also has awkward API issues. Clients shouldn't have to know about run loops in order to be called after a delay<sup><a href="#2014/a-new-kind-of-timer/fn2">2</a></sup> or on a periodic basis. In fact, there's a lot that can be safely removed from <tt>NSTimer</tt>'s API:</p> <p><ul> <li><span class="list"><em><tt>invalidate</tt></em>: Even though the timer won't necessarily be destroyed immediately, it has to be retained somewhere during its lifetime and checking <tt>if (self.timer != timer) { return; }</tt> is already a common and safe pattern for target-action style method invocations in Objective-C.</span></li> <li><span class="list"><em><tt>isValid</tt></em>: It's tempting to argue that non-repeating timers need this API, but its purpose in <tt>NSTimer</tt> is mainly to ensure that the timer isn't retaining the target anymore. The purpose of non-repeating timers is to cause side effects. One of those side effects should be to dispose of the timer.</span></li> <li><span class="list"><em>Non-repeating timers</em>: If a timer should only fire once, the method that it invokes can clean it up. If it's important that a timer existed in the past and did fire, then it's best to admit the extra bit of state as a property than to prolong the in-memory lifetime of an invalid, useless object.</span></li> <li><span class="list"><em>Run loops</em>: Timers shouldn't make threading guarantees. Since we're not in a perfect world, a good compromise is to offer the option for the timer to fire on either the main thread, or on a background thread.</span></li> <li><span class="list"><em><tt>NSInvocation</tt></em>: <tt>NSInvocation</tt> is an implementation detail of <tt>NSTimer</tt> and long-lived invocations are the root of its strong reference issues, since they only store argument and target references either strongly or unsafely. We could <a href="http://numist.net/post/2014/destroy-dealloc.html">rewrite it to reference its target weakly</a>, but invocations aren't used often enough to be worth it—<tt>NSTimer</tt> should support blocks instead.</span></li> <li><span class="list"><tt>fireDate</tt>: <tt>NSTimer</tt> supports this for irregular timers, and the same mechanism can be achieved by making the time interval a mutable property of the timer, further reducing the scope of the API. </ul></p> <p>These changes leave a simple new API that easily replaces <tt>NSTimer</tt>:</p> <p><pre class="textmate-source mac_classic"><span class="source source_objc"><span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>interface</span> <span class="entity entity_name entity_name_type entity_name_type_objc">NNTimer</span> <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">:</span> <span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc">NSObject</span><span class="meta meta_divider meta_divider_objc"> </span><span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"> <span class="meta meta_function meta_function_objc">+ <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span>NNTimer *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">scheduledTimerWithTimeInterval</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa">NSTimeInterval</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">seconds</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">block</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_posix-reserved support_type_posix-reserved_c">dispatch_block_t</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">block</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">queue</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_posix-reserved support_type_posix-reserved_c">dispatch_queue_t</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">queue</span></span>;</span> <span class="meta meta_function meta_function_objc">+ <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span>NNTimer *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">scheduledTimerWithTimeInterval</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa">NSTimeInterval</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">seconds</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">target</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">target</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">selector</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_objc">SEL</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">aSelector</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">userInfo</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">userInfo</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">queue</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_posix-reserved support_type_posix-reserved_c">dispatch_queue_t</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">queue</span></span>;</span> <span class="meta meta_property-with-attributes meta_property-with-attributes_objc"><span class="keyword keyword_other keyword_other_property keyword_other_property_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>property</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">(</span><span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">nonatomic</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">assign</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">readwrite</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">)</span></span> <span class="support support_type support_type_cocoa">NSTimeInterval</span> timeInterval; <span class="meta meta_property-with-attributes meta_property-with-attributes_objc"><span class="keyword keyword_other keyword_other_property keyword_other_property_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>property</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">(</span><span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">nonatomic</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">strong</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">readwrite</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">)</span></span> <span class="storage storage_type storage_type_id storage_type_id_objc">id</span> userInfo; <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">fire</span></span>;</span> </span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span></span></pre></p> <p>GCD and weak references didn't exist when <tt>NSTimer</tt> was created, so the resulting implementation is super simple:</p> <p><pre class="textmate-source mac_classic"><span class="source source_objc"><span class="meta meta_preprocessor meta_preprocessor_c meta_preprocessor_c_include">#<span class="keyword keyword_control keyword_control_import keyword_control_import_include keyword_control_import_include_c">import</span> <span class="string string_quoted string_quoted_double string_quoted_double_include string_quoted_double_include_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>NNTimer.h<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span></span> <span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>interface</span> <span class="entity entity_name entity_name_type entity_name_type_objc">NNTimer</span> <span class="meta meta_scope meta_scope_interface meta_scope_interface_objc">() <span class="meta meta_property-with-attributes meta_property-with-attributes_objc"><span class="keyword keyword_other keyword_other_property keyword_other_property_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>property</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">(</span><span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">nonatomic</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">readwrite</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">assign</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">)</span></span> <span class="support support_type support_type_cocoa support_type_cocoa_leopard">NSUInteger</span> mutationCounter; <span class="meta meta_property-with-attributes meta_property-with-attributes_objc"><span class="keyword keyword_other keyword_other_property keyword_other_property_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>property</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">(</span><span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">nonatomic</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">readonly</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">strong</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">)</span></span> <span class="support support_type support_type_posix-reserved support_type_posix-reserved_c">dispatch_queue_t</span> queue; <span class="meta meta_property-with-attributes meta_property-with-attributes_objc"><span class="keyword keyword_other keyword_other_property keyword_other_property_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>property</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">(</span><span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">nonatomic</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">readonly</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">strong</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">)</span></span> <span class="support support_type support_type_posix-reserved support_type_posix-reserved_c">dispatch_block_t</span> job; <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">_enqueueNextJob</span></span>;</span> </span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span> <span class="meta meta_implementation meta_implementation_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>implementation</span> <span class="entity entity_name entity_name_type entity_name_type_objc">NNTimer</span> <span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">+ <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span>NNTimer *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">scheduledTimerWithTimeInterval</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa">NSTimeInterval</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">seconds</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">block</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_posix-reserved support_type_posix-reserved_c">dispatch_block_t</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">block</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">queue</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_posix-reserved support_type_posix-reserved_c">dispatch_queue_t</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">queue</span></span>;</span> <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> NNTimer *result = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>NNTimer <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">new</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; result->_timeInterval = seconds; result->_job = block; result->_queue = queue; <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>result <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">_enqueueNextJob</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="keyword keyword_control keyword_control_c">return</span> result; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">+ <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span>NNTimer *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">scheduledTimerWithTimeInterval</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa">NSTimeInterval</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">seconds</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">target</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">target</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">selector</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_objc">SEL</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">aSelector</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">userInfo</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">userInfo</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">queue</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_posix-reserved support_type_posix-reserved_c">dispatch_queue_t</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">queue</span></span>;</span> <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> NNTimer *result = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="variable variable_language variable_language_objc">self</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">scheduledTimerWithTimeInterval<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>seconds <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">block<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="constant constant_language constant_language_objc">nil</span> <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">queue<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>queue</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; __weak <span class="storage storage_type storage_type_id storage_type_id_objc">id</span> weakTarget = target; __weak NNTimer *weakTimer = result; result->_job = ^<span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> __strong <span class="storage storage_type storage_type_id storage_type_id_objc">id</span> strongTarget = weakTarget; __strong NNTimer *strongTimer = weakTimer; <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>!strongTarget || !strongTimer) <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="keyword keyword_control keyword_control_c">return</span>; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span> <span class="punctuation punctuation_whitespace punctuation_whitespace_comment punctuation_whitespace_comment_leading punctuation_whitespace_comment_leading_c++"> </span><span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c++">//</span> Calling the IMP directly instead of using performSelector: or </span><span class="punctuation punctuation_whitespace punctuation_whitespace_comment punctuation_whitespace_comment_leading punctuation_whitespace_comment_leading_c++"> </span><span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c++">//</span> performSelector:withObject: in order to safely shut up the compiler </span><span class="punctuation punctuation_whitespace punctuation_whitespace_comment punctuation_whitespace_comment_leading punctuation_whitespace_comment_leading_c++"> </span><span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c++">//</span> warning about potentially-leaked objects. </span> <span class="storage storage_type storage_type_objc">IMP</span> imp = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>strongTarget <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">methodForSelector<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>aSelector</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">void</span> (</span>*imp1)(<span class="storage storage_type storage_type_id storage_type_id_objc">id</span>, <span class="storage storage_type storage_type_objc">SEL</span>, <span class="storage storage_type storage_type_id storage_type_id_objc">id</span>) = (<span class="storage storage_type storage_type_c">void</span> *)imp; <span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">imp1</span>(</span>strongTarget, aSelector, strongTimer); <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span>; result->_userInfo = userInfo; <span class="keyword keyword_control keyword_control_c">return</span> result; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">setTimeInterval</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_type support_type_cocoa">NSTimeInterval</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">timeInterval</span></span>;</span> <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> self->_timeInterval = timeInterval; self<span class="punctuation punctuation_separator punctuation_separator_variable-access punctuation_separator_variable-access_c">.</span><span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">mutationCounter</span>++; <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="variable variable_language variable_language_objc">self</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">_enqueueNextJob</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c++">//</span> -fire makes two mutually-exclusive promises. One is that the job is executed <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c++">//</span> synchronously, the other, less-obvious, promise is that the job is run on <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c++">//</span> the same queue (or in NSTimer's case, run loop) as the scheduled firings. <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c++">//</span> NSTimer opts for the simplest solution of keeping the synchronicity <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c++">//</span> guarantee, and so does NNTimer. </span><span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">fire</span></span>;</span> <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> self.<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">job</span>(</span>); <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">_enqueueNextJob</span></span>;</span> <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="support support_type support_type_cocoa">NSTimeInterval</span> nonNegativeTimeInterval = self<span class="punctuation punctuation_separator punctuation_separator_variable-access punctuation_separator_variable-access_c">.</span><span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">timeInterval</span> >= <span class="constant constant_numeric constant_numeric_c">0</span>. ? self<span class="punctuation punctuation_separator punctuation_separator_variable-access punctuation_separator_variable-access_c">.</span><span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">timeInterval</span> : <span class="constant constant_numeric constant_numeric_c">0</span>.; <span class="support support_type support_type_stdint support_type_stdint_c">int64_t</span> delta = nonNegativeTimeInterval * NSEC_PER_SEC; <span class="support support_type support_type_posix-reserved support_type_posix-reserved_c">dispatch_time_t</span> delay =<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">dispatch_time</span>(</span>DISPATCH_TIME_NOW, delta); <span class="support support_type support_type_cocoa support_type_cocoa_leopard">NSUInteger</span> mutationsAtSchedulingTime = self<span class="punctuation punctuation_separator punctuation_separator_variable-access punctuation_separator_variable-access_c">.</span><span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">mutationCounter</span>; __weak<span class="meta meta_initialization meta_initialization_c"> <span class="variable variable_other variable_other_c">__typeof</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>self) weakSelf = self; <span class="support support_type support_type_posix-reserved support_type_posix-reserved_c">dispatch_block_t</span> block = ^<span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> __strong<span class="meta meta_initialization meta_initialization_c"> <span class="variable variable_other variable_other_c">__typeof</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>self) strongSelf = weakSelf; <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>!strongSelf) <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="keyword keyword_control keyword_control_c">return</span>; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span> <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>mutationsAtSchedulingTime != strongSelf<span class="punctuation punctuation_separator punctuation_separator_variable-access punctuation_separator_variable-access_c">.</span><span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">mutationCounter</span>) <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="keyword keyword_control keyword_control_c">return</span>; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span> <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>strongSelf <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">fire</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>strongSelf <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">_enqueueNextJob</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span>; <span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">dispatch_after</span>(</span>delay, self<span class="punctuation punctuation_separator punctuation_separator_variable-access punctuation_separator_variable-access_c">.</span><span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">queue</span>, block); <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> </span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span> </span></pre></p> <p>Something shaped very much like this is going to land in <a href="https://github.com/numist/NNKit">NNKit</a> soon. Stay tuned!</p> <div class="footnotes"><hr /> <a name="2014/a-new-kind-of-timer/fn1"></a><sup>1</sup> <tt>NSFileHandle</tt> also implements <tt>close</tt>, the use of which leaves a useless dead object. If you find yourself using <tt>close</tt>, you have architectural problems.<br /> <a name="2014/a-new-kind-of-timer/fn2"></a><sup>2</sup> Before anyone says it, if you don't need invalidation, such as with delayed initialization, just use <tt>dispatch_after</tt>.<br /> </div> destroy dealloc tag:numist.net,2012-04-03:../post/2014/destroy-dealloc.html 2014-04-09T13:33:23-07:00 2014-04-07T10:00:00-07:00 Scott Perry http://numist.net/ spam@numist.net <p style="color:#999"><b>Note:</b> This blog post may contain video or JavaScript effects that are illegal in feeds and will be removed by most readers/aggregators. Some styling may also be lost, but it should display perfectly if you <a style="color:#999" href="../post/2014/destroy-dealloc.html">open it in your browser</a>.</p> <p>ARC obliterated entire classes of bugs by automating memory management in acyclic contexts and providing zeroing weak references. Thanks to this, many classes no longer need to perform any cleanup during object destruction. The most common reason for <tt>dealloc</tt> these days? Notifications.</p> <p>Broadcast messaging is vital to today's applications, but <tt>NSNotificationCenter</tt> has resisted modernization. Among its modern failings, its API <a href="http://subjective-objective-c.blogspot.com/2011/04/avoid-nsnotification-removeobserver.html">enables fragile usage</a> and it stores unsafe references to observers.</p> <p><a href="https://twitter.com/thekarladam">Karl</a> and I were discussing the error-prone nature of APIs that require bracketed calls, like mutexes that conform to <tt>NSLocking</tt><sup><a href="#2014/destroy-dealloc/fn1">1</a></sup> and <tt>addObserver:selector:name:object:</tt>/<tt>removeObserver:name:object:</tt>. He posed the question: how do we get rid of bracketing APIs? To start with, how can we make <tt>NSNotificationCenter</tt> support weak observers?</p> <!-- more --> <p>The answer, of course, is a proxy whose lifetime is tied to the observer using <a href="http://blog.andymatuschak.org/post/173646741/your-new-friends-obj-c-associated-objects">object association</a>:</p> <p><img src="../data/2014/destroy-dealloc/WeakProxy.png" width="416" height="59"></p> <p>The only API the proxy needs to provide is an initializer:</p> <p><pre class="textmate-source mac_classic"><span class="source source_objc"><span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>interface</span> <span class="entity entity_name entity_name_type entity_name_type_objc">NNWeakObserverProxy</span> <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">:</span> <span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_objc">NSProxy</span><span class="meta meta_divider meta_divider_objc"> </span><span class="meta meta_scope meta_scope_interface meta_scope_interface_objc"> <span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_objc">instancetype</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">initWithTarget</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSObject</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">target</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">selector</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_objc">SEL</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">selector</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">name</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSString</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">name</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">object</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">sender</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">addToNotificationCenter</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSNotificationCenter</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">notificationCenter</span></span>;</span> </span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span></span></pre></p> <p>The implementation is pretty simple: the proxy adds and removes itself from the notification center in its own initialization methods, the target is stored weakly so in the time between target and proxy destruction the message is safely dispatched to <tt>nil</tt>, and the message forwarding machinery is minimal.</p> <p><pre class="textmate-source mac_classic"><span class="source source_objc"><span class="meta meta_interface-or-protocol meta_interface-or-protocol_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>interface</span> <span class="entity entity_name entity_name_type entity_name_type_objc">NNWeakObserverProxy</span> <span class="meta meta_scope meta_scope_interface meta_scope_interface_objc">() <span class="meta meta_property-with-attributes meta_property-with-attributes_objc"><span class="keyword keyword_other keyword_other_property keyword_other_property_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>property</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">(</span><span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">nonatomic</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">readonly</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">weak</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">)</span></span> <span class="support support_class support_class_cocoa">NSObject</span> *target; <span class="meta meta_property-with-attributes meta_property-with-attributes_objc"><span class="keyword keyword_other keyword_other_property keyword_other_property_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>property</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">(</span><span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">nonatomic</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">readonly</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">assign</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">)</span></span> <span class="storage storage_type storage_type_objc">SEL</span> selector; <span class="meta meta_property-with-attributes meta_property-with-attributes_objc"><span class="keyword keyword_other keyword_other_property keyword_other_property_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>property</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">(</span><span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">nonatomic</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">readonly</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">strong</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">)</span></span> <span class="support support_class support_class_cocoa">NSString</span> *name; <span class="meta meta_property-with-attributes meta_property-with-attributes_objc"><span class="keyword keyword_other keyword_other_property keyword_other_property_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>property</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">(</span><span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">nonatomic</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">readonly</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">strong</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">)</span></span> <span class="storage storage_type storage_type_id storage_type_id_objc">id</span> sender; <span class="meta meta_property-with-attributes meta_property-with-attributes_objc"><span class="keyword keyword_other keyword_other_property keyword_other_property_objc"><span class="punctuation punctuation_definition punctuation_definition_keyword punctuation_definition_keyword_objc">@</span>property</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">(</span><span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">nonatomic</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">readonly</span>, <span class="keyword keyword_other keyword_other_property keyword_other_property_attribute">strong</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">)</span></span> <span class="support support_class support_class_cocoa">NSNotificationCenter</span> *notificationCenter; </span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span> <span class="meta meta_implementation meta_implementation_objc"><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>implementation</span> <span class="entity entity_name entity_name_type entity_name_type_objc">NNWeakObserverProxy</span> <span class="meta meta_scope meta_scope_implementation meta_scope_implementation_objc"> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_objc">instancetype</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">initWithTarget</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSObject</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">target</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">selector</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_objc">SEL</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">selector</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">name</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSString</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">name</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">object</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">sender</span></span> <span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc">addToNotificationCenter</span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="support support_class support_class_cocoa">NSNotificationCenter</span> *<span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">notificationCenter</span></span>;</span> <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> _target = target; _selector = selector; _name = name; _sender = sender; _notificationCenter = notificationCenter; <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>_notificationCenter <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">addObserver<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="variable variable_language variable_language_objc">self</span> <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">selector<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>_selector <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">name<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>_name <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">object<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>_sender</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="keyword keyword_control keyword_control_c">return</span> self; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_c">void</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">dealloc</span></span>;</span> <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>_notificationCenter <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">removeObserver<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="variable variable_language variable_language_objc">self</span> <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">name<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>_name <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">object<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>_sender</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> <span class="meta meta_section"><span class="meta meta_preprocessor meta_preprocessor_c">#<span class="keyword keyword_control keyword_control_import keyword_control_import_pragma keyword_control_import_pragma_c">pragma mark</span> <span class="meta meta_toc-list meta_toc-list_pragma-mark meta_toc-list_pragma-mark_c">Message forwarding</span></span></span> <span class="meta meta_function-with-body meta_function-with-body_objc"><span class="meta meta_function meta_function_objc">- <span class="meta meta_return-type meta_return-type_objc"><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_id storage_type_id_objc">id</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="entity entity_name entity_name_function entity_name_function_objc">forwardingTargetForSelector</span></span><span class="meta meta_argument-type meta_argument-type_objc"><span class="entity entity_name entity_name_function entity_name_function_name-of-parameter entity_name_function_name-of-parameter_objc"><span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_begin punctuation_definition_type_begin_objc">(</span><span class="storage storage_type storage_type_objc">SEL</span><span class="punctuation punctuation_definition punctuation_definition_type punctuation_definition_type_end punctuation_definition_type_end_objc">)</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_objc">aSelector</span></span>;</span> <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>aSelector == self<span class="punctuation punctuation_separator punctuation_separator_variable-access punctuation_separator_variable-access_c">.</span><span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">selector</span>) <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> <span class="keyword keyword_control keyword_control_c">return</span> self<span class="punctuation punctuation_separator punctuation_separator_variable-access punctuation_separator_variable-access_c">.</span><span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">target</span>; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span> <span class="keyword keyword_control keyword_control_c">return</span> self; <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span> </span><span class="storage storage_type storage_type_objc"><span class="punctuation punctuation_definition punctuation_definition_storage punctuation_definition_storage_type punctuation_definition_storage_type_objc">@</span>end</span></span></span></pre></p> <p>Lastly, a method in a category on <tt>NSNotificationCenter</tt> to tie it all together. Its primary responsibility is encapsulation, ensuring that the proxy's lifetime is tied as closely to the lifetime of the observer as possible:</p> <p><pre class="textmate-source mac_classic"><span class="source source_objc">- (<span class="storage storage_type storage_type_c">void</span>)nn_addWeakObserver:(<span class="storage storage_type storage_type_id storage_type_id_objc">id</span>)observer selector:(<span class="storage storage_type storage_type_objc">SEL</span>)selector name:(<span class="support support_class support_class_cocoa">NSString</span> *)name object:(<span class="storage storage_type storage_type_id storage_type_id_objc">id</span>)sender; <span class="meta meta_block meta_block_c"><span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_begin punctuation_section_block_begin_c">{</span> NNWeakObserverProxy *proxy = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span><span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">[</span>NNWeakObserverProxy <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">alloc</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">initWithTarget<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>observer <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">selector<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>selector <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">name<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>name <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">object<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>sender <span class="support support_function support_function_any-method support_function_any-method_name-of-parameter support_function_any-method_name-of-parameter_objc">addToNotificationCenter<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span><span class="variable variable_language variable_language_objc">self</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">]</span></span>; <span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">objc_setAssociatedObject</span>(</span>observer, (__bridge <span class="storage storage_modifier storage_modifier_c">const</span> <span class="storage storage_type storage_type_c">void</span> *)proxy, proxy, OBJC_ASSOCIATION_RETAIN); <span class="punctuation punctuation_section punctuation_section_block punctuation_section_block_end punctuation_section_block_end_c">}</span></span></span></pre></p> <p>This was simplified to fit in a blog post so it has a few limitations, such as the inability to remove the observation without destroying the observer itself, but it offers a glimpse into a future topic. Stay tuned!</p> <div class="edit"> <div class="editdate"><p class="editdate">edited on wednesday april 9<sup>th</sup>, 2014 at 13:33 (PDT):</p></div> <div class="editreason">Dave Lee <a href="https://twitter.com/kastiglione/status/453965456290762752">pointed out</a> that the proxy can use <tt>forwardingTargetForSelector:</tt> instead of <tt>forwardInvocation:</tt>. This is not only much faster, but also eliminates the need to cache the method signature. The code has been updated to take advantage of this. Thanks Dave!</div> </div> <div class="footnotes"><hr /> <a name="2014/destroy-dealloc/fn1"></a><sup>1</sup> Less error-prone approaches for mutexes include <tt>@synchronized</tt> and the modern APIs that take blocks<br /> </div> derry tag:numist.net,2012-04-03:../post/2014/derry.html 2014-03-15T20:11:23-07:00 2014-03-15T20:11:23-07:00 Scott Perry http://numist.net/ spam@numist.net <p>It's been a while since a photo post from our Europe trip, and the Derry portion would be best shared with a story. Especially like it because it illustrates how we travel. Not in vacation, but in life.</p> <p>We arrived in Derry by bus, and made our way to the hostel to drop off our backpacks before exploring. An old city by anyone's standards, Derry was a focal point for The Troubles, during which time the original city walls were augmented with solid metal and chain link spans to keep the nationalists and the unionists apart, with checkpoints at the openings. If you're paying attention to your surroundings, it's an unsettling place. The banners celebrating the "City of Culture's" upcoming events struck me as an intentional distraction to attract tourism, a veneer over a far more interesting place.</p> <p>While walking around the old walls that encircle the old city, we came across some youths that were burning a car. A fire truck had responded, and they'd forced it to turn back with thrown rocks. One of them threw a bicycle through the windshield, pulling it out soon after but not before the grease in the bearings had ignited. The others were kicking at the doors and body panels, jumping on the horizontal surfaces, and generally enjoying the destruction. I was carrying a 50 at the time, so I had to go down the hill and get a closer look. I made myself obvious before shooting, and they took the opportunity to cover up their faces.</p> <p><a href="../data/2014/derry/IMG_0787.jpg"><img src="../data/2014/derry/IMG_0787-medium.jpg" width="1023" height="682"></a></p> <p>Shortly after taking that photo my camera and I almost got taken out by a kid armed with a stick, and that emboldened the rest of them. I got out of there as calmly as possible to avoid inciting a chase as they yelled and threw rocks at me. Back at the top of the wall, one of the locals introduced himself to us, having decided from his vantage point that we were his kind of crazy. He worked as a community youth organizer—he recognized some of the kids from his program—with the goal of peacefully bridging the boundaries in the city. Basically, reducing the incidence of this kind of stuff. We got a walking tour from him that easily beat the other walking tours of the city.</p> <p>Night fell, we ate and returned to the hostel to sleep. Morning came, and we descended the stairs to the lounge to discover that it had been ransacked. The hostel had been burgled and all of the electronics stolen, including the phone I'd hidden behind the computer to charge. Everyone was a bit off-balance, and we got to talking about our experiences the day before. Someone recommended a pub for us to visit. We noted it, and walked to the police station to file a report first.</p> <p>We went to the police station to file a report and it was one of the oddest complexes I've ever visited, a modern fortress. If you arrived by car, you were allowed through an armoured blast door and <a href="http://www.deltascientific.com/hs_hb_dsc501.php">wedge barrier</a> into an enclosed space with another armoured blast door, which you weren't allowed through until the police were sure the vehicle was safe. The history of the Irish car bomb suddenly felt viscerally familiar. Walk-ups were subject to slightly more relaxed security, though I noticed that there was always a minimum of bulletproof glass between us and the officers on duty. We filed an unremarkable report that would never help us get any closer to our stuff.</p> <p>The pub that we'd been directed to was fairly deep in a nationalist area of the city, and it fell silent the moment we entered. The bar was dark wood, the wall behind it mirrored, and the barkeep and clientele decidedly Irish. A massive flag of Ireland hung on the wall opposite the bar. There were two free stools, so we sidled up and ordered pints of Guinness and Smithwick's. The man sitting next to me broke the silence once we'd had a sip, and asked where we were from. Cognizant of our experiences over the last 24 hours I said, "I'm Canadian," to which he immediately replied, "oh, happy day!" and everyone in the pub fell back into easy conversations with each other. They paid for our drinks.</p> <p><a href="../data/2014/derry/IMG_0790.jpg"><img src="../data/2014/derry/IMG_0790-medium.jpg" width="1024" height="507"></a>"</p> <p>We shared our travel experiences thus far in Ireland, having visited both the nation and the territory, and got a local's perspective on things in return. The kids were mostly upset because they'd grown up in angry households, but the parents were violent for a cause; kids these days are angry, but the violence is senseless, untargeted. People were still fighting for nationalism, and a new form of IRA was coming about, but they were extremists and the real fight was being waged mostly with currency and politics, not weapons. As we asked questions, they increasingly responded with not answers, but stories. They made a point to note that they were all peaceful these days. What a strange thing to say. My instincts told me that we were onto something; at this point the parlance was especially curious, authoritative. Having made enough hints without a negative reaction, my new barmate took us to the flag on the wall and moved it aside, revealing a collage of photos from the 70s, 80s, and 90s. Promonently placed was a photo of him, a lit Molotov in one hand as he ran towards a British tank to scoop a child from its path. It looked like an image search for <a href="https://www.google.com/search?q=troubles&client=safari&rls=en&source=lnms&tbm=isch&sa=X&ei=cw0lU-fEMNHwoATelIL4BA&ved=0CAkQ_AUoAQ&biw=1366&bih=696#q=%22The+Troubles%22+Derry&rls=en&tbm=isch">The Troubles in Derry</a>, and the faces in those photos were recognizably sitting at the bar behind us. We learned history from the people who made it.</p> sunset piano tag:numist.net,2012-04-03:../post/2013/sunset-piano.html 2013-09-02T09:18:53-07:00 2013-09-02T09:18:53-07:00 Scott Perry http://numist.net/ spam@numist.net <p><a href="../data/2013/sunset-piano/9656218553_466f0a0a32_o.jpg"><img src="../data/2013/sunset-piano/9656218553_466f0a0a32_o.jpg" width="1024" height="576"></a></p> a t o tag:numist.net,2012-04-03:../post/2013/a-t-o.html 2013-03-11T16:59:09-07:00 2013-03-11T16:59:09-07:00 Scott Perry http://numist.net/ spam@numist.net <p><a href="../data/2013/a-t-o/9659447040_9c6eace70f_o.jpg"><img src="../data/2013/a-t-o/9659447040_9c6eace70f_o.jpg" width="1024" height="683"></a></p> trailing governments tag:numist.net,2012-04-03:../post/2013/trailing-governments.html 2013-02-04T11:58:23-08:00 2013-02-04T11:58:23-08:00 Scott Perry http://numist.net/ spam@numist.net <p style="color:#999"><b>Note:</b> This blog post may contain video or JavaScript effects that are illegal in feeds and will be removed by most readers/aggregators. Some styling may also be lost, but it should display perfectly if you <a style="color:#999" href="../post/2013/trailing-governments.html">open it in your browser</a>.</p> <blockquote><p>“It’s really hard for the government to censor things when they don’t understand the made-up words or meaning behind the imagery,” said Kevin Lee, COO of China Youthology, in conversation at the DLD conference in Munich on Monday. “The people there aren’t even relying on text anymore It’s audio, visual, photos. All the young people are creating their own languages.”<cite><a href="http://allthingsd.com/20130122/toward-a-more-visual-language-how-social-networks-skirt-censorship-in-china/">Mike Isaac, AllThingsD</a> via <a href="http://www.schneier.com/blog/archives/2013/02/using_imagery_t.html">Bruce Schneier</a></cite></p></blockquote> <p>Combined with an <a href="http://www.schneier.com/blog/archives/2013/02/pentagon_staffs.html">earlier article</a> written by Schneier, speak to an unsurprising and systematic lack of understanding of technology by the government, and I think this scales well to any person in a position of leadership who doesn't really care about the issues at hand. Cybersecurity initiatives are a great way for representatives to gerrymander benefits for their constituents, but I'm not convinced that many of them actually understand what they're talking about.</p> <p>My dad, a professor of engineering at SJSU, does care about the topics he teaches, and I'm often the target of his questions. Some time ago, he asked me to formalise a definition for The Cloud. First, my father is a more advanced troll than I ever realised.Second, exploring this was a journey though people's misunderstandings of technology—as you'd expect from formalising any buzzword.</p> <p>The cloud used to be the server side of a client-server relationship, with an emphasis on server clusters and massive scalability. As the term caught on and became a buzzword, and as many of my friends and I were working at VMware at the time—a company that was in a unique place to provide private cloud solutions—we quickly started using The Cloud as an expletive when something was broken or someone was making buzzword gumbo. Thus I can now define The Cloud as:</p> <p><ol><li><span class="list">The component in a product or service which, when broken, cannot be fixed by even the most competent end user.</span></li> <li><span class="list">Magical marketing fairy dust.</span></li></ol></p> visiting cities in ireland tag:numist.net,2012-04-03:../post/2013/visiting-cities-in-ireland.html 2013-02-02T20:54:38-08:00 2013-02-02T20:54:38-08:00 Scott Perry http://numist.net/ spam@numist.net Our next stop was Ireland, so there was a lot of travelling. By foot IMG_0387.jpg By rail IMG_5853.jpg And by plane (not pictured). We found Ireland very welcoming to travellers, even the children were happy to see us. IMG_0092.jpg <!-- more --> In Dublin, we stayed at a place we'd booked via AirBnB, partially due to the promise of tea and soda bread every morning. IMG_5889.jpg In the spirit of underpromising and overdelivering, our host was fostering A KITTEN! IMG_0125.jpg Until visiting, I didn't <em>really</em> appreciate the importance of music in Irish culture. Music is everything and everywhere in this place, and it's great. Even the buskers were talented and well-practiced. IMG_5909.jpg And obviously a visit to the capital of Ireland wouldn't have been complete without some dancing. IMG_0356.jpg Unfortunately, we discovered that foreigners outnumber Irish folk in Dublin. One night, the only Irish in our pub were the waitstaff and the musicians, so we decided we should move on to get a better feel for the country and its people.