<?xml version="1.0" encoding="UTF-8"?>

<feed xmlns="http://www.w3.org/2005/Atom">

<title>briankc.com</title>

<link href="http://briankc.com/atom.xml" rel="self"/>
<link href="http://briankc.com/"/>

<updated>2011-03-23T18:44:13-04:00</updated>

<id>http://briankc.com/</id>
<author>
	<name>Brian Christensen</name>
	<email>brian@briankc.com</email>
</author>


<entry>
	<title>Using blocks as a flexible callback mechanism</title>
	<link href="http://briankc.com/2009/09/13/using-blocks-as-a-flexible-callback-mechanism/"/>
	<updated>2009-09-13T00:00:00-04:00</updated>
	<id>http://briankc.com/2009/09/13/using-blocks-as-a-flexible-callback-mechanism</id>
	<content type="html">&lt;p&gt;Among the many numerous developer improvements in Snow Leopard is the &lt;a href=&quot;http://developer.apple.com/mac/articles/cocoa/introblocksgcd.html&quot;&gt;addition of blocks&lt;/a&gt; to the Objective-C language (now at version 2.1). While working on some networking code using &lt;code&gt;NSURLConnection&lt;/code&gt; I discovered that blocks provide a beautiful and flexible mechanism for implementing callbacks.&lt;/p&gt;

&lt;p&gt;As a quick example, let’s say you want to initiate two GET requests to different websites. Perhaps the first is to post some form data and the other is just to download the website content. No matter the particular specifics, the idea is that for different types of &lt;code&gt;NSURLConnection&lt;/code&gt; requests you will want to respond differently upon completion. For the first you might want to update the UI to show that the form data was posted. For the second you may want to display the site in a web view. To accomplish this you would traditionally need to keep an array around to hold not only the &lt;code&gt;NSURLConnection&lt;/code&gt; instances themselves, but some kind of associated identifier for each one. Otherwise, when your delegate methods fire you will have no idea which action initiated the request in the first place &amp;mdash; and thusly you wouldn’t necessarily know what to do next after the connection is finished loading.&lt;/p&gt;

&lt;p&gt;The following is a bit of untested pseudo-code (a rough approximation if you will) of one of the traditional methods of handling this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;objc&quot;&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;performMyFirstRequest&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NSURLRequest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLRequest&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;requestWithURL:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myFirstURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NSURLConnection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLConnection&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;connectionWithRequest:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; 
                                         &lt;span class=&quot;nl&quot;&gt;delegate:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
 
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_connections&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;addObject:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSDictionary&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;dictionaryWithObject:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
       &lt;span class=&quot;s&quot;&gt;@&amp;quot;NSURLConnection&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&amp;quot;myFirstRequestIdentifier&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&amp;quot;identifier&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;performMySecondRequest&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NSURLRequest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLRequest&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;requestWithURL:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mySecondURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NSURLConnection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLConnection&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;connectionWithRequest:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; 
                                         &lt;span class=&quot;nl&quot;&gt;delegate:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;  
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_connections&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;addObject:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSDictionary&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;dictionaryWithObject:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
       &lt;span class=&quot;s&quot;&gt;@&amp;quot;NSURLConnection&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&amp;quot;someOtherIdentifierHere&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&amp;quot;identifier&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;connection:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLConnection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt; 
           &lt;span class=&quot;nl&quot;&gt;didReceiveResponse:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NSDictionary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connectionInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;_infoForConnection:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NSString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identifier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connectionInfo&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;objectForKey:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&amp;quot;identifier&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
 
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identifier&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;isEqualToString:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&amp;quot;myFirstRequestIdentifier&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&amp;quot;The first request was successful!&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// do something else&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identifier&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;isEqualToString:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&amp;quot;someOtherIdentifierHere&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&amp;quot;The second request was successful!&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
 
  &lt;span class=&quot;c&quot;&gt;// Remember to remove the connectionInfo dictionary from our _connections &lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;// ivar once the connection is finished loading&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSDictionary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;_infoForConnection:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLConnection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSDictionary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connectionInfo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_connections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connectionInfo&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;objectForKey:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&amp;quot;NSURLConnection&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;connectionInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;In short, you will have to have a bunch of conditional if-else statements in order to properly respond to each different connection’s completion. The alternative approach is to write a &lt;code&gt;URLConnectionManager&lt;/code&gt; class based on blocks:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;objc&quot;&gt;&lt;span class=&quot;c&quot;&gt;// URLConnectionManager.h&lt;/span&gt;
 
&lt;span class=&quot;k&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;URLConnectionManager&lt;/span&gt; : &lt;span class=&quot;nc&quot;&gt;NSObject&lt;/span&gt; 
 
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;performRequest:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLRequest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; 
         &lt;span class=&quot;nl&quot;&gt;responseBlock:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;responseBlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 
&lt;span class=&quot;k&quot;&gt;@end&lt;/span&gt;
 
&lt;span class=&quot;c&quot;&gt;// URLConnectionManager.m&lt;/span&gt;
 
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;performRequest:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLRequest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; 
         &lt;span class=&quot;nl&quot;&gt;responseBlock:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;responseBlock&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NSURLConnection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLConnection&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;connectionWithRequest:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; 
                                          &lt;span class=&quot;nl&quot;&gt;delegate:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;associateValue:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;responseBlock&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;withKey:&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&amp;quot;responseBlock&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;connection:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLConnection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt; 
           &lt;span class=&quot;nl&quot;&gt;didReceiveResponse:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;responseBlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;associatedValueForKey:&lt;/span&gt;
                                                   &lt;span class=&quot;s&quot;&gt;@&amp;quot;responseBlock&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;responseBlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This code also takes advantage of associated objects, another new language feature that allows us to avoid having to keep an array of connection info dictionaries around to store the associated &lt;code&gt;responseBlock&lt;/code&gt; reference. (I am using an &lt;a href=&quot;http://blog.andymatuschak.org/post/173646741/your-new-friends-obj-c-associated-objects&quot;&gt;elegant category wrapper of the C API written by Andy Matuschak&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Using this approach, the two connection requests can be implemented as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;objc&quot;&gt;&lt;span class=&quot;c&quot;&gt;// The first request&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;NSURLRequest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLRequest&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;requestWithURL:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myFirstURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
 
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connectionManager&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;performRequest:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; 
                    &lt;span class=&quot;nl&quot;&gt;responseBlock:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&amp;quot;Received a response from myFirstURL: %ld %@&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSHTTPURLResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;// Perform whatever other specific magic you need for this response!&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}];&lt;/span&gt;
 
&lt;span class=&quot;c&quot;&gt;// The second request&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;NSURLRequest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLRequest&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;requestWithURL:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mySecondURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
 
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connectionManager&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;performRequest:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; 
                    &lt;span class=&quot;nl&quot;&gt;responseBlock:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSURLResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&amp;quot;Received a response from mySecondURL: %ld %@&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSHTTPURLResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;// Perform whatever other specific magic you need for this response!&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Note that there are no more if-else statements to deal with and even though the requests are being performed asynchronously, you can write a piece of code to deal with the response in the same spot that you make the initial connection invocation. This results in a much cleaner and more readable codebase.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/briankc/blocks-sample&quot;&gt;Browse and/or download the full Xcode sample project on GitHub&lt;/a&gt;&lt;/p&gt;
</content>
</entry>

<entry>
	<title>Why support matters</title>
	<link href="http://briankc.com/2009/04/08/why-support-matters/"/>
	<updated>2009-04-08T00:00:00-04:00</updated>
	<id>http://briankc.com/2009/04/08/why-support-matters</id>
	<content type="html">&lt;p&gt;I’ve been a happy paid user of &lt;a href=&quot;http://macrabbit.com/cssedit/&quot;&gt;CSSEdit 2&lt;/a&gt; for well over two years now. So when MacRabbit released &lt;a href=&quot;http://macrabbit.com/espresso/&quot;&gt;Espresso&lt;/a&gt; it seemed only logical for me to try it out. I used it for about a week until I deemed it fit for purchase. I sauntered on over to the &lt;a href=&quot;http://macrabbit.com/store/&quot;&gt;MacRabbit online store&lt;/a&gt; and discovered (as pretty much expected) that there was a discount purchase option for current CSSEdit 2 owners (at 49.95€ rather than the full 59.95€). To qualify one has to enter a valid CSSEdit 2 license code, so I dutifully looked mine up in my e-mail archives, copied it, and pasted it into the appropriate text field.&lt;/p&gt;

&lt;p&gt;But instead of allowing me to complete the order I was greeted by a message stating that my license code &amp;ldquo;is not a valid CSSEdit 2 code.&amp;rdquo; Of course, I knew this claim to be false since this is the same code that works just fine in my still functioning copy of CSSEdit. Just to be sure though I headed on over to the MacRabbit support page where I hoped the license code lookup form would offer some kind of resolution. I entered my e-mail address (which I double-checked in my mail archives to be the one I originally used to register CSSEdit) to have my code sent to me. That didn’t quite work:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&amp;ldquo;Couldn’t find anything with this e-mail address! Are you sure it is correct?&amp;rdquo;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;The next step was to shoot off an e-mail to the support people:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Subject: &lt;strong&gt;Espresso discount for CSSEdit 2 owners&lt;/strong&gt;&lt;br/&gt;
Date: March 24, 2009 22:43:36 EDT&lt;/p&gt;

&lt;p&gt;Hi,&lt;/p&gt;

&lt;p&gt;I am trying to purchase Espresso via the CSSEdit 2 discount option. The form, however, is not accepting my license code:&lt;/p&gt;

&lt;p&gt;Name: (redacted)
Code: (redacted)&lt;/p&gt;

&lt;p&gt;It claims this is not a valid CSSEdit 2 license code. Furthermore, I don’t appear to be in your lost code lookup database either.&lt;/p&gt;

&lt;p&gt;Thanks.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Indeed, I sent this on March 24th. Somewhere around three weeks later I was left wondering if MacRabbit even has any support people. But just to be sure, I sent a follow-up on April 6th.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Subject: &lt;strong&gt;Re: Espresso discount for CSSEdit 2 owners&lt;/strong&gt;&lt;br/&gt;
Date: April 6, 2009 18:17:59 EDT&lt;/p&gt;

&lt;p&gt;A reply would be most appreciated as there are only 2 more days left in the trial period.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Since I have fit Espresso nicely into my workflow for several projects and its trial period is not of infinite duration, I had to make a choice. Either I could buy it at the full price of 59.95€ and be done with it, or I could partake of the &lt;a href=&quot;http://macheist.com/&quot;&gt;MacHeist 3 bundle&lt;/a&gt; to get a license for considerably less than even the discount option I was initially trying to use. I wasn’t originally looking to get the MacHeist bundle since I would rather just directly pay the authors of the one application I actually need. Quality software development is hard work and developing a good application can take an inordinate amount of time, so I don’t mind rewarding such effort by paying a fair price.&lt;/p&gt;

&lt;p&gt;Alas, quality software is a package deal. If I am going to pay a quality price I expect a certain basic level of support. It is rather difficult to justify paying full price for a piece of software when the support part of it is not being handled very well (or, seemingly, not being handled at all). Therefore, I went with the MacHeist bundle. The outcome is quite favorable for me as I can continue using Espresso to get work done. I can’t say it is nearly as favorable for MacRabbit’s cashflow.&lt;/p&gt;

&lt;p&gt;It is certainly not my intent to bludgeon MacRabbit with this. They make fine software. But they do need to tighten up ship a bit, for their own sake.&lt;/p&gt;
</content>
</entry>

<entry>
	<title>Switching to Google Reader</title>
	<link href="http://briankc.com/2009/03/31/switching-to-google-reader/"/>
	<updated>2009-03-31T00:00:00-04:00</updated>
	<id>http://briankc.com/2009/03/31/switching-to-google-reader</id>
	<content type="html">&lt;p&gt;For several years now I have been using &lt;a href=&quot;http://cynicalpeak.com/cyndicate/&quot;&gt;Cyndicate&lt;/a&gt; as my RSS feed reader. It is an excellent piece of software, but I have come to realize that I really don’t use any of the features that make the application so unique among its competition. I don’t use any filters, I don’t use ratings, and though I was taking advantage of its persistent architecture by filing interesting articles into various folders for future reference, it is a very rare occasion that I ever go into these archives to re-read anything I put there.&lt;/p&gt;

&lt;p&gt;The most important thing I have been wanting for some time is something Cyndicate doesn’t offer right now. And that is the ability to synchronize across multiple devices. In particular I want to be able to check my feeds on my iPhone or MacBook Pro when I am away from my desktop machine. Sometimes I’d like to skim or even read read posts while standing in line.&lt;/p&gt;

&lt;p&gt;In short, I have decided to switch to Google Reader for all of my subscriptions. Not content with using the web interface, however, I am trying out &lt;a href=&quot;http://thecosmicmachine.com/&quot;&gt;EventBox&lt;/a&gt; on the Mac side of this; for the iPhone it is &lt;a href=&quot;http://www.phantomfish.com/byline.html&quot;&gt;Byline&lt;/a&gt;. Neither of these applications is really a terribly impressive fit and I will definitely miss Cyndicate’s persistence and overall polish. But for now this looks like a trade-off I am willing to deal with.&lt;/p&gt;
</content>
</entry>

<entry>
	<title>The trouble with Adobe</title>
	<link href="http://briankc.com/2008/09/21/the-trouble-with-adobe/"/>
	<updated>2008-09-21T00:00:00-04:00</updated>
	<id>http://briankc.com/2008/09/21/the-trouble-with-adobe</id>
	<content type="html">&lt;p&gt;I can’t remember a time when any one of &lt;a href=&quot;http://adobe.com/&quot;&gt;Adobe’s&lt;/a&gt; Mac applications had an interface that felt like it truly belonged on my Mac. I don’t recall the problems being as pronounced in the pre-Mac OS X days, but there were always &amp;mdash; at best &amp;mdash; annoying quirks to be found. At worst, using their software made me feel like punching my computer screen.&lt;/p&gt;

&lt;p&gt;But then Adobe brought their suite of applications to Mac OS X, and things got even worse. And ever since, they’ve spent each successive release screwing up their user experience with remarkable consistency. It’s to the point that the thought of punching my screen isn’t even enough. I want to reach into my Mac and beat the living snot out of every piece of the Adobe Creative Suite 3 I can find.&lt;/p&gt;

&lt;p&gt;And, predictably, &lt;a href=&quot;http://blogs.adobe.com/jnack/2008/06/future_photoshop_ui.html&quot;&gt;if the Fireworks CS4 beta is an indicator of what’s going to happen to the rest of the suite&lt;/a&gt;, Adobe obviously still doesn’t get it. Sadly, if a company has spent this many decades in the business and continues to utterly fail in this respect, it may be safe to bet they never will get it either.&lt;/p&gt;

&lt;p&gt;Because when it comes down to it, I don’t need a window whose title bar is lacking a title and has instead been cluttered with a bunch of toolbar icons and a &amp;ldquo;mode&amp;rdquo; pop-up menu. In fact, I don’t even want a bunch of confusing interface &amp;ldquo;modes&amp;rdquo; to choose from. I don’t particularly care about throwing the palettes and everything else into one gigantic tabbed window. All of that is nothing more than extraneous fluff that’s detracting attention and resources away from what really needs to be fixed.&lt;/p&gt;

&lt;p&gt;It is especially ironic that &lt;a href=&quot;http://blogs.adobe.com/jnack/2008/06/future_photoshop_ui.html&quot;&gt;John Nack cites Panic’s Coda&lt;/a&gt; as an example of a single window application, because &lt;a href=&quot;http://panic.com/&quot;&gt;Panic&lt;/a&gt; would never ship something this utterly tasteless (not even as an internal beta, much less a public one). If you’re looking to Panic for inspiration, emulate their attention to detail. The suite’s problem isn’t that it needs a revolutionary new interface concept. Quite the opposite, in fact. The focus needs to be on the little things, because they all add up to one big mess of inconsistency and annoyance.&lt;/p&gt;

&lt;p&gt;Perhaps Adobe needs to acquire some semblance of taste before worrying about tabbed windows and monkeying with title bars.&lt;/p&gt;
</content>
</entry>

<entry>
	<title>Lipstick on a pig</title>
	<link href="http://briankc.com/2008/09/12/lipstick-on-a-pig/"/>
	<updated>2008-09-12T00:00:00-04:00</updated>
	<id>http://briankc.com/2008/09/12/lipstick-on-a-pig</id>
	<content type="html">&lt;p&gt;Daniel Jalkut brings up some interesting points &lt;a href=&quot;http://www.red-sweater.com/blog/553/microsoft-ads-are-genius&quot;&gt;in his analysis of the new Microsoft ads&lt;/a&gt;. But I have to disagree with his fundamental assertion that the ad campaign is &amp;ldquo;genius.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Far from it, in fact. For those who haven’t seen them yet, there are two spots out already. &lt;a href=&quot;http://www.youtube.com/watch?v=11NOblvuEpU&quot;&gt;In the first&lt;/a&gt;, Bill Gates and Jerry Seinfeld go to a shoe store. &lt;a href=&quot;http://www.youtube.com/watch?v=AJlaW0D-t9Q&quot;&gt;In the second&lt;/a&gt;, the two live in some random family’s house. Neither ad appears to be actively marketing or selling anything. Jalkut counters this criticism by noting that the purpose is to build Microsoft’s image and brand, to &amp;ldquo;alter the long-term impression of the company that develops and markets the world’s leading desktop computer operating system.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;This would be fine, if it weren’t for the fact that Microsoft’s current perception is a direct result of its incompetently executed product line. The Zune continues to be a relative failure, seemingly everyone hates Vista, and its successor Windows 7 is, predictably, nowhere in sight. Releasing a lofty series of advertising spots with the goal of showing us some kind of kinder and gentler Microsoft will fall flat on its face without the product teeth to back it.&lt;/p&gt;

&lt;p&gt;On the bright side, neither spot feels nor looks cheaply made. Bill Gates is better at acting than most people might expect. And the ads do have some funny moments. But the biggest problem isn’t the artistic quality of these clips. The issue is the deep disconnect going on between the &amp;ldquo;we’re cool&amp;rdquo; image that Microsoft is trying to push and the reality of what the company actually is.&lt;/p&gt;

&lt;p&gt;Maybe this campaign is actually the signal of a Microsoft rebirth. That is, however, unlikely, especially given that Steve Ballmer is still the boss. Fundamental cultural shifts like this don’t usually happen without an executive shakeup, starting at the top. Some people are comparing these TV spots to Apple’s &amp;ldquo;Think Different&amp;rdquo; campaign. Yet they seem to conveniently forget that &amp;ldquo;Think Different&amp;rdquo; came onto the stage just as Gil Amelio was leaving it, among many other changes at the company’s core.&lt;/p&gt;

&lt;p&gt;Until I see something similar happen at Microsoft, I don’t think this is much different than an artistically well-made Soviet government propaganda piece. And just like people found the same old regime hiding behind those, they will see that behind that pleasant, occasionally funny dialogue between Gates and Seinfeld still stands the same old Microsoft.&lt;/p&gt;

&lt;p&gt;In the end, no matter how much lipstick you put on that pig, you’re still left with a pig.&lt;/p&gt;
</content>
</entry>

<entry>
	<title>A new platform in just a weekend</title>
	<link href="http://briankc.com/2008/07/09/a-new-platform-in-just-a-weekend/"/>
	<updated>2008-07-09T00:00:00-04:00</updated>
	<id>http://briankc.com/2008/07/09/a-new-platform-in-just-a-weekend</id>
	<content type="html">&lt;p&gt;Jesse Ezell believes it is too much to expect software developers moving to a new platform &lt;a href=&quot;http://weblogs.asp.net/jezell/archive/2008/07/06/iphone-sdk.aspx&quot;&gt;to spend more than a weekend learning the language, API, and tools&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Honestly, I don’t think most developers could get up and running with the SDK in a weekend and it’s a lot to ask to have people pour a lot of effort into an application without knowing whether it will actually be accepted.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;To be fair, &amp;ldquo;get up and running&amp;rdquo; could mean a number of things. But the rest of his blog post is written in a tone which suggests that taking up iPhone development with no prior experience in Objective-C or Mac development should really be just that easy. Yet, software engineering requires &amp;ldquo;a lot of effort&amp;rdquo; on any platform. It is not outlandish to expect anyone who is serious about development &amp;mdash; on the iPhone or elsewhere &amp;mdash; to spend more than just a weekend getting up to speed with his new environment. (There’s a reason 464 page books are written on the subject. Hats off to anyone who can get through all that in a weekend.)&lt;/p&gt;

&lt;p&gt;Ezell goes on to write about the model-view-controller design pattern:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;The UI libraries are strictly MVC. You have no other good option. Either you write MVC, or you go home.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Not only is MVC a good choice for architecting solid applications, it is by far a superior alternative to the sort of schizophrenic &amp;ldquo;options&amp;rdquo; disaster Ezell is seeking. Perhaps going home is worth considering after all.&lt;/p&gt;

&lt;p&gt;But the biggest indicator that Ezell just doesn’t &amp;ldquo;get it&amp;rdquo; is this:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;As far as I could tell, the interface builder doesn’t really store the interface in a useful form. Early on, I tried to drag some buttons around and then go look at what it generated; but, as far as I could tell, the IDE appears to put the UI in some kind of resource file instead of generating something you can hand modify later.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;The value of a generative approach in this situation is questionable. If any properties of these buttons need to be modified later, then the answer is to go back into Interface Builder and perform the modifications. The fact that a user interface designed in IB isn’t &amp;ldquo;hand modifiable&amp;rdquo; is not a bad thing. That this is even brought up as a criticism seems to strongly indicate a mental barrier erected by developers who want everything on the Mac and/or iPhone to be the same as what they are already familiar with, rather than a problem with Apple’s development tools.&lt;/p&gt;
</content>
</entry>

<entry>
	<title>Trial versions in the iPhone App Store</title>
	<link href="http://briankc.com/2008/06/26/trial-versions-in-the-iphone-app-store/"/>
	<updated>2008-06-26T00:00:00-04:00</updated>
	<id>http://briankc.com/2008/06/26/trial-versions-in-the-iphone-app-store</id>
	<content type="html">&lt;p&gt;Paul Kafasis lists a number of &lt;a href=&quot;http://blogs.oreilly.com/iphone/2008/06/open-questions-for-the-app-sto.html&quot;&gt;&amp;ldquo;Open Questions for The App Store&amp;rdquo;&lt;/a&gt; over at the Inside iPhone Blog. In particular, he asks about trial versions of software made available through the store:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;We provide free trials of all our software for Mac and Windows. Just like test-driving a car, you can test our software, before you buy it. The goal here is to make sure our users know just what they’re getting, and that it will perform as expected. How will we accomplish this in the App Store? Can we have free software that’s just a trial, and then link it to a paid version?&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Commenter &lt;a href=&quot;http://www.mitchcohen.com/&quot;&gt;Mitch Cohen&lt;/a&gt; replies:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;The general consensus for trials seems to be to have two versions on the App Store – a trial and a real version.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;I’ve been hoping since the announcement of the App Store that this isn’t how trial versions will be handled, as I believe this to be a completely uninspired approach to the problem. Why is there a need for two separate downloads? There should really only be one, which is automatically swapped for the full version if the user chooses to purchase the app.&lt;/p&gt;

&lt;p&gt;Conceptually, I don’t see why it needs to be any different than an app on the Mac that you can &amp;ldquo;unlock&amp;rdquo; with a license code. Only that in this case you’d unlock it through the App Store, obviating the need for entering codes. Whether a new binary is actually downloaded and installed behind the scenes should be an implementation detail that need not concern the user.&lt;/p&gt;
</content>
</entry>

<entry>
	<title>Preliminary notes on Aperture 2.0 plug-ins</title>
	<link href="http://briankc.com/2008/02/13/preliminary-notes-on-aperture-20-plug-ins/"/>
	<updated>2008-02-13T00:00:00-05:00</updated>
	<id>http://briankc.com/2008/02/13/preliminary-notes-on-aperture-20-plug-ins</id>
	<content type="html">&lt;p&gt;Many Aperture users are starting to get excited about the upcoming Aperture 2 plug-in SDK. I think some people are expecting this to be some kind of &amp;ldquo;adjustments&amp;rdquo; API, perhaps allowing you to add additional effects filters on top of the standard adjustments like white balance, exposure, and so on.&lt;/p&gt;

&lt;p&gt;Unfortunately, from what I’ve been able to figure out, the SDK will not support non-destructive adjustments. It doesn’t ask the plug-in to &amp;ldquo;apply&amp;rdquo; its changes anywhere in the current chain of non-destructive adjustments or anything of the sort. It creates a copy of the selected photo, lets the plug-in do whatever it does to that copy, and that’s pretty much it. So, if the user does some exposure adjustments, then uses some type of :filter effect&quot; edit plug-in, and finally applies a few more standard (ie. contrast) adjustments, he won’t be able to change the initial exposure adjustments and have them reflected in the &amp;ldquo;edited&amp;rdquo; copy.&lt;/p&gt;

&lt;p&gt;Using class-dump we can see that the following is all a plug-in appears to be able to do:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;objc&quot;&gt;&lt;span class=&quot;k&quot;&gt;@protocol&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApertureEditPlugIn&lt;/span&gt;
 
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;initWithAPIManager:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PROAPIAccessing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;apiManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;editManager:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApertureEditManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;editManager&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;didImportImageAtPath:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagePath&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;versionUniqueID:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;versionUniqueID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;beginEditSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;editWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 
&lt;span class=&quot;k&quot;&gt;@end&lt;/span&gt;
 
&lt;span class=&quot;k&quot;&gt;@protocol&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApertureEditManager&lt;/span&gt;
 
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;selectedVersionIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;editableVersionIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;importedVersionIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;propertiesWithoutThumbnailForVersion:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;thumbnailForVersion:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp8&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;size:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;editableVersionsOfVersions:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp8&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;stackWithOriginal:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;canImport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;importImageAtPath:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp8&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;referenced:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp12&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;stackWithVersions:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;deleteVersions:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;addCustomMetadata:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp8&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;toVersions:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;addHierarchicalKeywords:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp8&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;toVersions:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;apertureWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endEditSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cancelEditSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 
&lt;span class=&quot;k&quot;&gt;@end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;To get at the data required to actually perform any &amp;ldquo;edits&amp;rdquo; on the image, you have to send the editManager an &lt;code&gt;editableVersionsOfVersions:stackWithOriginal:&lt;/code&gt; message. This causes Aperture to create copies of the requested images. That’s all the plug-in is then able to work with.&lt;/p&gt;

&lt;p&gt;I’d love to be completely wrong on this, but it appears that these &amp;ldquo;edit&amp;rdquo; plug-ins won&amp;rsquo;t be that much different than using &amp;ldquo;open with external editor.&amp;rdquo; This isn’t looking to be nearly as powerful or &amp;ldquo;revolutionary&amp;rdquo; as a lot of folks are hoping for, I’m afraid.&lt;/p&gt;
</content>
</entry>

<entry>
	<title>Thoughts on the MWSF ‘08 keynote</title>
	<link href="http://briankc.com/2008/01/20/thoughts-on-the-mwsf-08-keynote/"/>
	<updated>2008-01-20T00:00:00-05:00</updated>
	<id>http://briankc.com/2008/01/20/thoughts-on-the-mwsf-08-keynote</id>
	<content type="html">&lt;p&gt;It seems only logical to write a post-”Stevenote” analysis following my &lt;a href=&quot;http://briankc.com/2008/01/14/the-eve-of-macworld-2008/&quot;&gt;obligatory Macworld 2008 predictions entry&lt;/a&gt; from last week. Complete rundowns of the keynote have been hashed out ad nauseam across the internet, so I will limit myself to just two points of interest.&lt;/p&gt;

&lt;h3&gt;The state of the Mac OS&lt;/h3&gt;

&lt;p&gt;Steve Jobs started off by reporting that Apple had so far shipped 5 million copies of Leopard, making this &amp;ldquo;the most successful release of Mac OS X ever.&amp;rdquo; According to Jobs, this constitutes 20% of the Mac OS X installed base. As a developer currently working on a Leopard-only product, I find these numbers to be outstanding news. &lt;a href=&quot;http://wilshipley.com/&quot;&gt;Wil Shipley&lt;/a&gt; of &lt;a href=&quot;http://delicious-monster.com/&quot;&gt;Delicious Monster&lt;/a&gt; has noted several times that the type of users who quickly upgrade to the latest operating system are the ones willing to spend money on software, and as such constitute a terrific target audience for new applications.&lt;/p&gt;

&lt;p&gt;One can only imagine what numbers Jobs will reveal at the WWDC ‘08 keynote this summer.&lt;/p&gt;

&lt;h3&gt;The MacBook Air&lt;/h3&gt;

&lt;p&gt;Unsurprisingly, the complaints, the incessant whining, and the usual proclamations of Apple’s impending doom due to the introduction of the &lt;a href=&quot;http://www.apple.com/macbookair/&quot;&gt;MacBook Air&lt;/a&gt; are running rampant across the web. Price comparisons between it and other MacBook models are being used to justify claims that the machine is &amp;ldquo;overpriced&amp;rdquo; and &amp;ldquo;underpowered.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Granted, the Air is obviously less powerful than its MacBook (Pro) counterparts and it does indeed cost more. But engineering a notebook to fit into the constraints this product dictated doesn’t happen by itself. Hardware engineers don’t work for free. Miniaturization is always expensive. Historically, notebooks have been less powerful than their desktop counterparts, yet tended to cost quite a bit more. Portability comes at a premium.&lt;/p&gt;

&lt;p&gt;John Gruber &lt;a href=&quot;http://daringfireball.net/2008/01/macbook_air&quot;&gt;published his take&lt;/a&gt; on the MacBook Air in which he says that it is &amp;ldquo;clearly designed as a secondary machine, not a main machine.&amp;rdquo; While I agree that this statement holds true for power users, I also think Scott Stevenson &lt;a href=&quot;http://theocacao.com/document.page/545&quot;&gt;makes an excellent point&lt;/a&gt; that &amp;ldquo;there’s an entire category of users that could use this not just as their primary, but their only computer.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;I don’t know if the MacBook Air will be a bestseller, but I do predict it&amp;rsquo;ll be a success.&lt;/p&gt;
</content>
</entry>

<entry>
	<title>The eve of Macworld 2008</title>
	<link href="http://briankc.com/2008/01/14/the-eve-of-macworld-2008/"/>
	<updated>2008-01-14T00:00:00-05:00</updated>
	<id>http://briankc.com/2008/01/14/the-eve-of-macworld-2008</id>
	<content type="html">&lt;p&gt;With the Stevenote less than twenty-four hours away, it’s high time for the obligatory Macworld Eve post.&lt;/p&gt;

&lt;p&gt;The big item that seems to be circulating the rumor sites is the so-called &amp;ldquo;MacBook Air.&amp;rdquo; While I think that name sounds rather pedestrian, there does appear to be some circumstantial evidence supporting the idea. But regardless of its title, I am betting we will be seeing some sort of slimmed-down MacBook, probably lacking an optical drive. &lt;a href=&quot;http://log.carpeaqua.com/post/23700504&quot;&gt;Justin Williams has an interesting take&lt;/a&gt; on how this could be accomplished by Apple introducing a new digital software distribution model. I agree with John Gruber &lt;a href=&quot;http://daringfireball.net/2008/01/macworld_expo_predictions&quot;&gt;that it will feature a standard hard disk, not flash memory&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We may also see an updated iPhone. Revised Cinema Displays seem likely as well, along with a new Apple TV.&lt;/p&gt;

&lt;p&gt;In any case, I’m sure it will be interesting. I’ll be following along via &lt;a href=&quot;http://www.macrumorslive.com/&quot;&gt;MacRumorsLive&lt;/a&gt;. Hopefully some people will be &amp;ldquo;&lt;a href=&quot;http://twitter.com/&quot;&gt;twittering&lt;/a&gt;&amp;rdquo; live from the keynote as it unfolds, too.&lt;/p&gt;
</content>
</entry>

<entry>
	<title>Create a transparent fullscreen view</title>
	<link href="http://briankc.com/2007/12/15/create-a-transparent-fullscreen-view/"/>
	<updated>2007-12-15T00:00:00-05:00</updated>
	<id>http://briankc.com/2007/12/15/create-a-transparent-fullscreen-view</id>
	<content type="html">&lt;p&gt;The question of how to create a transparent fullscreen view came up on the cocoa-dev list recently. As it turns out, it is fairly trivial to implement.&lt;/p&gt;

&lt;h3&gt;The custom window subclass&lt;/h3&gt;

&lt;p&gt;Create the following header file:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;objc&quot;&gt;&lt;span class=&quot;lineno&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// TransparentWindow.h&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;2&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;#import &amp;lt;Cocoa/Cocoa.h&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;4&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TransparentWindow&lt;/span&gt; : &lt;span class=&quot;nc&quot;&gt;NSWindow&lt;/span&gt; 
&lt;span class=&quot;lineno&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;8&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt;9&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;@end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;In the implementation all we need to do to make the window transparent is specify a &lt;code&gt;NSBorderlessWindowMask&lt;/code&gt; and set the background color to &lt;code&gt;[NSColor clearColor]&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;objc&quot;&gt;&lt;span class=&quot;lineno&quot;&gt; 1&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// TransparentWindow.m&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt; 3&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;#import &amp;quot;TransparentWindow.h&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt; 5&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;@implementation&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TransparentWindow&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt; 7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;initWithContentRect:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSRect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contentRect&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;styleMask:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSUInteger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aStyle&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;backing:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSBackingStoreType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bufferingType&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;defer:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;initWithContentRect:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSScreen&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mainScreen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;styleMask:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSBorderlessWindowMask&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;backing:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bufferingType&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;defer:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt;11&lt;/span&gt;     &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;13&lt;/span&gt;         &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;setBackgroundColor:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSColor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clearColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]];&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14&lt;/span&gt;         &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;setOpaque:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt;17&lt;/span&gt;     &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;19&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;@end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h3&gt;Using the window class&lt;/h3&gt;

&lt;p&gt;To use this window you can either instantiate it programmatically or set it as the custom window class in your NIB file (I am using the latter method myself in a current project).&lt;/p&gt;

&lt;p&gt;If you need a semi-transparent window, you can substitute something like &lt;code&gt;[NSColor colorWithCalibratedWhite:1.0 alpha:0.5]&lt;/code&gt; for the color object in line 13.&lt;/p&gt;

&lt;p&gt;And, depending on what you are doing, you may want your window to appear above the menubar. To do so, add &lt;code&gt;[self setLevel:NSMainMenuWindowLevel + 1];&lt;/code&gt; after line 14.&lt;/p&gt;
</content>
</entry>


</feed>

