<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"> 
  <id>http://oleb.net/blog/</id>
  <title>Ole Begemann: iOS Development</title>
  <subtitle>A blog about programming in Objective-C and Cocoa (Touch) for iOS and Mac OS X.</subtitle>
  <link href='http://oleb.net/blog/atom.xml' rel="self" />
  <link rel="alternate" href='http://oleb.net/' type="text/html" />
  <updated>2012-02-22T17:55:00Z</updated>
  <author>
    <name>Ole Begemann</name>
    <email>ole@oleb.net</email>
  </author>
  <rights>Copyright © 2009–2011 Ole Begemann</rights>

  <entry>
    <id>http://oleb.net/blog/2012/02/checking-code-signing-and-sandboxing-status-in-code/</id>
    <title>Checking Code Signing and Sandboxing Status in Code</title>
    <published>2012-02-22T17:55:00Z</published>
    <updated>2012-02-23T15:00:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2012/02/checking-code-signing-and-sandboxing-status-in-code/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2012/02/checking-code-signing-and-sandboxing-status-in-code/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p class=&quot;update&quot;&gt;&lt;strong&gt;Update February 23, 2012:&lt;/strong&gt; I put the code for the category on GitHub and added a corresponding link to the article. I also added a custom prefix to the category methods to avoid possible namespace problems.&lt;/p&gt;

&lt;h1&gt;The codesign Utility&lt;/h1&gt;

&lt;p&gt;On the command line, you can use the &lt;code&gt;codesign&lt;/code&gt; utility to check whether a Mac app is signed. For example,
&lt;code&gt;codesign --display --verbose=4 /Applications/Preview.app&lt;/code&gt; will display a whole lot of info about Preview’s code signature:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Executable=/Applications/Preview.app/Contents/MacOS/Preview
Identifier=com.apple.Preview
Format=bundle with Mach-O universal (i386 x86_64)
CodeDirectory v=20100 size=12266 flags=0x0(none) hashes=605+5 location=embedded
Hash type=sha1 size=20
CDHash=c8a47e06c8372dca11ab0bf03f121e1f69638a54
Signature size=4064
Authority=Software Signing
Authority=Apple Code Signing Certification Authority
Authority=Apple Root CA
Info.plist entries=32
Sealed Resources rules=12 files=172
Internal requirements count=1 size=1144
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also use &lt;code&gt;codesign&lt;/code&gt; to determine whether an app is sandboxed and, if so, list its sandboxing entitlements. The command &lt;code&gt;codesign --display --entitlements - /Applications/Preview.app&lt;/code&gt; will display the contents of the entitlements property list that is embedded in the application binary:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Executable=/Applications/Preview.app/Contents/MacOS/Preview
??qq?&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&amp;gt;
&amp;lt;plist version=&quot;1.0&quot;&amp;gt;
&amp;lt;dict&amp;gt;
    &amp;lt;key&amp;gt;com.apple.security.app-sandbox&amp;lt;/key&amp;gt;
    &amp;lt;true/&amp;gt;
    &amp;lt;key&amp;gt;com.apple.security.files.user-selected.read-write&amp;lt;/key&amp;gt;
    &amp;lt;true/&amp;gt;
    &amp;lt;key&amp;gt;com.apple.security.device.camera&amp;lt;/key&amp;gt;
    &amp;lt;true/&amp;gt;
    &amp;lt;key&amp;gt;com.apple.security.print&amp;lt;/key&amp;gt;
    &amp;lt;true/&amp;gt;
    &amp;lt;key&amp;gt;com.apple.security.app-protection&amp;lt;/key&amp;gt;
    &amp;lt;true/&amp;gt;
    &amp;lt;key&amp;gt;com.apple.security.camera&amp;lt;/key&amp;gt;
    &amp;lt;true/&amp;gt;
    &amp;lt;key&amp;gt;com.apple.security.documents.user-selected.read-write&amp;lt;/key&amp;gt;
    &amp;lt;true/&amp;gt;
    &amp;lt;key&amp;gt;com.apple.security.temporary-exception.mach-lookup.global-name&amp;lt;/key&amp;gt;
    &amp;lt;array&amp;gt;
        &amp;lt;string&amp;gt;com.apple.systemuiserver.screencapture&amp;lt;/string&amp;gt;
    &amp;lt;/array&amp;gt;
&amp;lt;/dict&amp;gt;
&amp;lt;/plist&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;Doing it in Code&lt;/h1&gt;

&lt;p&gt;Can we do the same in code? Yes we can. With a lot of help from my coworkers &lt;a href=&quot;http://www.joergjacobsen.com/&quot;&gt;Jörg Jacobsen&lt;/a&gt; (see &lt;a href=&quot;https://github.com/iMediaSandboxing/XPCKit&quot;&gt;his work on XPC and Sandboxing&lt;/a&gt; for the iMedia framework) and &lt;a href=&quot;http://chbeer.de/&quot;&gt;Christian Beer&lt;/a&gt; (who pointed me to the &lt;a href=&quot;http://opensource.apple.com/source/security_systemkeychain/security_systemkeychain-39457/src/&quot;&gt;source code for the &lt;code&gt;codesign&lt;/code&gt; utility&lt;/a&gt;), I wrote a category on &lt;code&gt;NSBundle&lt;/code&gt; that can tell you for any application bundle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether it has a valid code signature,&lt;/li&gt;
  &lt;li&gt;whether it is sandboxed and&lt;/li&gt;
  &lt;li&gt;whether it was downloaded from the Mac App Store.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The public interface for the category looks like this and should be self-explanatory:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl slc&quot;&gt;// NSBundle+OBCodeSigningInfo.h&lt;/span&gt;
&lt;span class=&quot;hl kwa&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;hl kwb&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    OBCodeSignStateUnsigned &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl num&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt;
    OBCodeSignStateSignatureValid&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt;
    OBCodeSignStateSignatureInvalid&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt;
    OBCodeSignStateSignatureNotVerifiable&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt;
    OBCodeSignStateSignatureUnsupported&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt;
    OBCodeSignStateError
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt; OBCodeSignState&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;hl kwc&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;NSBundle&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;OBCodeSigningInfo&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;ob_comesFromAppStore&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;ob_isSandboxed&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;OBCodeSignState&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;ob_codeSignState&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;hl kwc&quot;&gt;@end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Code Signing Services&lt;/h2&gt;

&lt;p&gt;For the implementation, we need to look at the &lt;a href=&quot;https://developer.apple.com/library/mac/#documentation/Security/Reference/CodeSigningRef/Reference/reference.html&quot;&gt;Code Signing Services&lt;/a&gt; in the Security framework. The &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Security/Reference/CodeSigningRef/Reference/reference.html#//apple_ref/c/func/SecStaticCodeCreateWithPath&quot;&gt;&lt;code&gt;SecStaticCodeCreateWithPath()&lt;/code&gt;&lt;/a&gt; takes the URL of an app bundle and returns a reference to a so-called static code object that represents the bundle’s code. We can then call the function &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Security/Reference/CodeSigningRef/Reference/reference.html#//apple_ref/c/func/SecStaticCodeCheckValidityWithErrors&quot;&gt;&lt;code&gt;SecStaticCodeCheckValidityWithErrors()&lt;/code&gt;&lt;/a&gt; on the static code object to obtain information about its code signature.&lt;/p&gt;

&lt;h2&gt;Additional Requirements for the Signature (Sandboxing)&lt;/h2&gt;

&lt;p&gt;To determine whether an app is sandboxed, we can call &lt;code&gt;SecStaticCodeCheckValidityWithErrors()&lt;/code&gt; again, this time with the additional code requirement (passed as the third argument to the function) that the code object contains a certain entitlement (which is &lt;code&gt;com.apple.security.app-sandbox&lt;/code&gt; in our case). The call to create this requirement looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl kwb&quot;&gt;static&lt;/span&gt; SecRequirementRef sandboxRequirement &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; NULL&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl kwd&quot;&gt;SecRequirementCreateWithString&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwd&quot;&gt;CFSTR&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl str&quot;&gt;&quot;entitlement[&lt;/span&gt;&lt;span class=&quot;hl esc&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;hl str&quot;&gt;com.apple.security.app-sandbox&lt;/span&gt;&lt;span class=&quot;hl esc&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;hl str&quot;&gt;] exists&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;),&lt;/span&gt; kSecCSDefaultFlags&lt;span class=&quot;hl opt&quot;&gt;, &amp;amp;&lt;/span&gt;sandboxRequirement&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Have a look at the &lt;a href=&quot;https://developer.apple.com/library/mac/#documentation/Security/Conceptual/CodeSigningGuide/RequirementLang/RequirementLang.html&quot;&gt;documentation for the Code Signing Requirement Language&lt;/a&gt; to learn how to formulate other requirements you might have.&lt;/p&gt;

&lt;h2&gt;Mac App Store Receipt Check&lt;/h2&gt;

&lt;p&gt;The implementation of the last method, &lt;code&gt;-ob_comesFromAppStore&lt;/code&gt;, is rather unrelated. It simply checks whether the bundle contains a Mac App Store receipt. OS X 10.7 has a special method to find the App Store receipt in the bundle: &lt;a href=&quot;https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSBundle_Class/Reference/Reference.html#//apple_ref/doc/uid/20000214-DontLinkElementID_1&quot;&gt;&lt;code&gt;appStoreReceiptURL&lt;/code&gt;&lt;/a&gt;. If 10.6 compatibility is important for you, you have to hard-code the path to the receipt at &lt;code&gt;Contents/_MASReceipt/receipt&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;The Source Code&lt;/h2&gt;

&lt;p&gt;Check out the full source code of the category below. I use &lt;a href=&quot;https://developer.apple.com/library/mac/#DOCUMENTATION/Cocoa/Conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html&quot;&gt;associative references&lt;/a&gt; to cache the values of some variables that I use in multiple places, such as the code signature state. &lt;span class=&quot;update&quot;&gt;&lt;strong&gt;Update February 23, 2012:&lt;/strong&gt; The code is now also &lt;a href=&quot;https://github.com/ole/NSBundle-OBCodeSigningInfo&quot;&gt;available on GitHub&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl slc&quot;&gt;// NSBundle+OBCodeSigningInfo.m&lt;/span&gt;
&lt;span class=&quot;hl ppc&quot;&gt;#import&lt;/span&gt; &lt;span class=&quot;hl pps&quot;&gt;&quot;NSBundle+OBCodeSigningInfo.h&quot;&lt;/span&gt;&lt;span class=&quot;hl ppc&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;hl ppc&quot;&gt;#import &amp;lt;Security/SecRequirement.h&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hl ppc&quot;&gt;#import &amp;lt;objc/runtime.h&amp;gt;&lt;/span&gt;


&lt;span class=&quot;hl kwc&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;NSBundle&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;OBCodeSigningInfoPrivateMethods&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;SecStaticCodeRef&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;ob_createStaticCode&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;SecRequirementRef&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;ob_sandboxRequirement&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl kwc&quot;&gt;@end&lt;/span&gt;


&lt;span class=&quot;hl kwc&quot;&gt;@implementation&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;NSBundle&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;OBCodeSigningInfo&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;ob_comesFromAppStore
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl slc&quot;&gt;// Check existence of Mac App Store receipt&lt;/span&gt;
    NSURL &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;appStoreReceiptURL &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; appStoreReceiptURL&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    NSFileManager &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;fileManager &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSFileManager alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;BOOL&lt;/span&gt; appStoreReceiptExists &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;fileManager fileExistsAtPath&lt;span class=&quot;hl opt&quot;&gt;:[&lt;/span&gt;appStoreReceiptURL path&lt;span class=&quot;hl opt&quot;&gt;]];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; appStoreReceiptExists&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;ob_isSandboxed
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;BOOL&lt;/span&gt; isSandboxed &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; NO&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; ob_codeSignState&lt;span class=&quot;hl opt&quot;&gt;] ==&lt;/span&gt; OBCodeSignStateSignatureValid&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
        SecStaticCodeRef staticCode &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; ob_createStaticCode&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
        SecRequirementRef sandboxRequirement &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; ob_sandboxRequirement&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;staticCode &lt;span class=&quot;hl opt&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; sandboxRequirement&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
            OSStatus codeCheckResult &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;SecStaticCodeCheckValidityWithErrors&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;staticCode&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; kSecCSBasicValidateOnly&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; sandboxRequirement&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; NULL&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;codeCheckResult &lt;span class=&quot;hl opt&quot;&gt;==&lt;/span&gt; errSecSuccess&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
                isSandboxed &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; YES&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;hl kwd&quot;&gt;CFRelease&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;staticCode&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; isSandboxed&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;OBCodeSignState&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;ob_codeSignState
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl slc&quot;&gt;// Return cached value if it exists&lt;/span&gt;
    &lt;span class=&quot;hl kwb&quot;&gt;static const void&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;kOBCodeSignStateKey&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    NSNumber &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;resultStateNumber &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;objc_getAssociatedObject&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; kOBCodeSignStateKey&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;resultStateNumber&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
        &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;resultStateNumber integerValue&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;hl slc&quot;&gt;// Determine code sign status&lt;/span&gt;
    OBCodeSignState resultState &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; OBCodeSignStateError&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    SecStaticCodeRef staticCode &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; ob_createStaticCode&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;staticCode&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
        OSStatus signatureCheckResult &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;SecStaticCodeCheckValidityWithErrors&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;staticCode&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; kSecCSBasicValidateOnly&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; NULL&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; NULL&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;hl kwa&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;signatureCheckResult&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
            &lt;span class=&quot;hl kwa&quot;&gt;case&lt;/span&gt; errSecSuccess&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt; resultState &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; OBCodeSignStateSignatureValid&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;hl kwa&quot;&gt;case&lt;/span&gt; errSecCSUnsigned&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt; resultState &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; OBCodeSignStateUnsigned&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;hl kwa&quot;&gt;case&lt;/span&gt; errSecCSSignatureFailed&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;hl kwa&quot;&gt;case&lt;/span&gt; errSecCSSignatureInvalid&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;
                resultState &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; OBCodeSignStateSignatureInvalid&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;hl kwa&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;hl kwa&quot;&gt;case&lt;/span&gt; errSecCSSignatureNotVerifiable&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt; resultState &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; OBCodeSignStateSignatureNotVerifiable&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;hl kwa&quot;&gt;case&lt;/span&gt; errSecCSSignatureUnsupported&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt; resultState &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; OBCodeSignStateSignatureUnsupported&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;hl kwa&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt; resultState &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; OBCodeSignStateError&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;hl kwd&quot;&gt;CFRelease&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;staticCode&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
        resultState &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; OBCodeSignStateError&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;hl slc&quot;&gt;// Cache the result&lt;/span&gt;
    resultStateNumber &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSNumber numberWithInteger&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;resultState&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwd&quot;&gt;objc_setAssociatedObject&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; kOBCodeSignStateKey&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; resultStateNumber&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; OBJC_ASSOCIATION_RETAIN&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; resultState&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;hl ppc&quot;&gt;#pragma mark - Private helper methods&lt;/span&gt;

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;SecStaticCodeRef&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;ob_createStaticCode
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    NSURL &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;bundleURL &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; bundleURL&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    SecStaticCodeRef staticCode &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; NULL&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl kwd&quot;&gt;SecStaticCodeCreateWithPath&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;((&lt;/span&gt;__bridge CFURLRef&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;bundleURL&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; kSecCSDefaultFlags&lt;span class=&quot;hl opt&quot;&gt;, &amp;amp;&lt;/span&gt;staticCode&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; staticCode&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;SecRequirementRef&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;ob_sandboxRequirement
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl kwb&quot;&gt;static&lt;/span&gt; SecRequirementRef sandboxRequirement &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; NULL&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl kwb&quot;&gt;static&lt;/span&gt; dispatch_once_t onceToken&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl kwd&quot;&gt;dispatch_once&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&amp;amp;&lt;/span&gt;onceToken&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; ^&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;hl kwd&quot;&gt;SecRequirementCreateWithString&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwd&quot;&gt;CFSTR&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl str&quot;&gt;&quot;entitlement[&lt;/span&gt;&lt;span class=&quot;hl esc&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;hl str&quot;&gt;com.apple.security.app-sandbox&lt;/span&gt;&lt;span class=&quot;hl esc&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;hl str&quot;&gt;] exists&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;),&lt;/span&gt; kSecCSDefaultFlags&lt;span class=&quot;hl opt&quot;&gt;, &amp;amp;&lt;/span&gt;sandboxRequirement&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; sandboxRequirement&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;hl kwc&quot;&gt;@end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2012/02/passing-data-between-view-controllers/</id>
    <title>Passing Data Between View Controllers</title>
    <published>2012-02-21T19:10:00Z</published>
    <updated>2012-02-24T11:40:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2012/02/passing-data-between-view-controllers/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2012/02/passing-data-between-view-controllers/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;A very common pattern on iOS is for one view controller to react to a user action (such as tapping on a button or table cell) by creating and presenting another view controller. In code, this looks something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;IBAction&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;nextScreenButtonTapped&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;sender
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    DestinationViewController &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;destinationController &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;DestinationViewController alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.navigationController pushViewController&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;destinationController animated&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;YES&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In all but the simplest cases this code is not sufficient because we usually have to configure the new screen before we present it. The calling view controller (&lt;code&gt;self&lt;/code&gt; in this context) has information that needs to be shown on the view that is to be presented by the new view controller. Let’s assume the destination view contains a text field whose text must be set. Since the text field can be accessed via a public property in &lt;code&gt;DestinationViewController&lt;/code&gt;, many beginners extend the code in the most straightforward way: just set the text field’s text directly from the source view controller.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;IBAction&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;nextScreenButtonTapped&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;sender
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    DestinationViewController &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;destinationController &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;DestinationViewController alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    destinationController.nameTextField.text &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.myModel.name&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.navigationController pushViewController&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;destinationController animated&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;YES&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;Don’t Misuse Views For Storing Data&lt;/h1&gt;

&lt;p&gt;This approach fails because at the time the line &lt;code&gt;destinationController.nameTextField.text = ...&lt;/code&gt; is executed, the &lt;code&gt;DestinationViewController&lt;/code&gt;’s view has not yet been loaded and therefore the text field (one of the controller’s view’s subviews) does not yet exist. &lt;code&gt;nameTextField&lt;/code&gt; will be &lt;code&gt;nil&lt;/code&gt; and the line of code above does nothing. Now, the easiest way to fix this is to make sure the view controller’s view gets loaded before the code is executed. You can do this by accessing the view controller’s &lt;code&gt;view&lt;/code&gt; property, which automatically will attempt to load the view:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;IBAction&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;nextScreenButtonTapped&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;sender
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    DestinationViewController &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;destinationController &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;DestinationViewController alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;destinationController.view&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
        destinationController.nameTextField.text &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.myModel.name&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.navigationController pushViewController&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;destinationController animated&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;YES&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now this works, but you should not do it this way. There are at least three reasons why this piece of code is bad design:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
    &lt;p&gt;To people who don’t know that accessing the &lt;code&gt;view&lt;/code&gt; property implicitly loads the view, this code is very obscure. Why the need for the &lt;code&gt;if (destinationController.view) { ... }&lt;/code&gt; statement? The could would require an explanatory comment to make its purpose clear. If you find yourself having to add comments to simple-looking code, it is often a sign of bad design. In my opinion, the vast majority of your code should be able to explain itself without any comments.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It breaks encapsulation. A view controller’s view and all its subviews should only be accessed by the view controller that owns these objects. It is that view controller’s job and sole responsibility to manage its view(s), and no other object should have to interfere in this relationship. Instead, the view controller should offer a clean public interface to allow outside objects to configure it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You must not use views to store data. In this example, the &lt;code&gt;nameTextField&lt;/code&gt; is the only object managed by the view controller that stores the string to be edited. This is an absolute no-go. It is not only bad design in the model-view-controller context but can also potentially lead to data loss. In iOS, view controllers are expected to destroy their views under memory pressure when those views are not currently visible. If this happens to a text field that is the sole storage for an edited model property, data has been lost.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;&lt;h1&gt;The Solution&lt;/h1&gt;

&lt;p&gt;The solution for this problem is to declare another public property &lt;code&gt;NSString *name&lt;/code&gt; in the &lt;code&gt;DestinationViewController&lt;/code&gt; class and assign the data to this property first:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;IBAction&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;nextScreenButtonTapped&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;sender
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    DestinationViewController &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;destinationController &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;DestinationViewController alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    destinationController.name &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.myModel.name&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.navigationController pushViewController&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;destinationController animated&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;YES&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, in &lt;code&gt;-[DestinationViewController viewDidLoad]&lt;/code&gt;, we know the view (and with it our text field) has been loaded and we can assign the text to the text field:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;viewDidLoad
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;super&lt;/span&gt; viewDidLoad&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.nameTextField.text &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.name&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The view controller must also take care to update its &lt;code&gt;name&lt;/code&gt; property whenever the user edits the text in the text field. That way, the &lt;code&gt;name&lt;/code&gt; property acts as storage for the user’s data and the view controller remains in a safe state when its view gets unloaded.&lt;/p&gt;

&lt;div class=&quot;update&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Update February 24, 2012:&lt;/strong&gt; Several people have pointed out to me that there are other ways to pass data to the target view controller that in many cases might even be better. One such method is to define a custom &lt;code&gt;init...&lt;/code&gt; method in the target view controller that takes the data the view controller needs as arguments. This makes the purpose of the class even clearer and does avoid possible problems when another object assign a new value to the property when the view is already on screen. In code, this would look like this:&lt;/p&gt;

  &lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;IBAction&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;nextScreenButtonTapped&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;sender
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    DestinationViewController &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;destinationController &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;DestinationViewController alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; 
        initWithName&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.myModel.name&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.navigationController pushViewController&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;destinationController animated&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;YES&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;p&gt;And in &lt;code&gt;DestinationViewController.m&lt;/code&gt;:&lt;/p&gt;

  &lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl slc&quot;&gt;// DestinationViewController.m&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;initWithName&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;NSString &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;theName
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;super&lt;/span&gt; initWithNibName&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;DestinationViewController&quot;&lt;/span&gt; bundle&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
        _name &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;theName copy&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;viewDidLoad
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;super&lt;/span&gt; viewDidLoad&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.nameTextField.text &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; _name&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;p&gt;Others proposed to declare a custom datasource protocol that &lt;code&gt;DestinationViewController&lt;/code&gt; uses to obtain the data it needs from its data source (usually its parent view controller), much like &lt;code&gt;UITableView&lt;/code&gt; works. This is also a good suggestion. It involves a few more lines of code but makes the coupling between the objects even looser.&lt;/p&gt;

  &lt;p&gt;Finally, several readers asked me why I opted to pass &lt;code&gt;self.myModel.name&lt;/code&gt; to the destination view controller instead of passing the entire model object (&lt;code&gt;self.myModel&lt;/code&gt;). Both are definitely possible. Which approach is the better one depends on the purpose of the destination view controller in my opinion. If the view controller is designed to display and/or edit all or most of the model object’s attributes, it is definitely better to pass the whole object along. On the other hand, if the view controller is a generic editing controller whose purpose is to edit an arbitrary string, you should just pass this string to it. In this case, the destination view controller should not need to know anything about the model object whose attribute it edits.&lt;/p&gt;

  &lt;p&gt;Thanks to everybody who sent in their comments.&lt;/p&gt;
&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2012/02/what-ios-should-learn-from-android-and-windows-8/</id>
    <title>What iOS Should Learn from Android and Windows 8</title>
    <published>2012-02-20T20:05:00Z</published>
    <updated>2012-02-20T20:05:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2012/02/what-ios-should-learn-from-android-and-windows-8/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2012/02/what-ios-should-learn-from-android-and-windows-8/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;Following up on my post about &lt;a href=&quot;/blog/2012/02/share-sheets-only-half-way-there/&quot;&gt;the new Share sheets in Mountain Lion and what they might mean for the future of content sharing in iOS&lt;/a&gt;, let’s take a more technical look at how Apple’s competition implements content sharing across apps. In this article, I will first investigate how Android and Windows 8 solve the issue and then hopefully come to a conclusion what Apple could learn and/or adopt from these implementations.&lt;/p&gt;

&lt;p&gt;Note that I am no expert on either of the two platforms so my remarks will probably contain some mistakes. I will gladly update the post with any corrections you send me.&lt;/p&gt;

&lt;h1&gt;Android&lt;/h1&gt;

&lt;h2&gt;Activities&lt;/h2&gt;

&lt;div class=&quot;with-caption align-right&quot; style=&quot;width:200px;&quot;&gt;
  &lt;p&gt;&lt;img src=&quot;/media/android-app-sharing-text.png&quot; alt=&quot;Android displaying a list of apps that can receive the content to be shared.&quot;&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;Android displaying a list of apps that can receive the content to be shared.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;A typical Android app consists of several so-called &lt;a href=&quot;http://developer.android.com/guide/topics/fundamentals/activities.html&quot;&gt;Activities&lt;/a&gt;. An activity is an app component that provides a single screen&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; in an app and manages how users can interact with this screen. As such, the concept is somewhat comparable to &lt;a href=&quot;https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007457-CH1-SW1&quot;&gt;view controllers in iOS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But there is an important difference: while iOS view controllers are pretty tightly coupled to the app they belong to, activities on Android are more loosely bound to each other. An Android app can not only launch its own activities but also access and launch activities that have been provided by other apps. This way, activities from many different apps can end up on the activity stack. The user can use the device’s back button to navigate back up the stack, thereby implicitly switching from app to app.&lt;/p&gt;

&lt;p&gt;Android uses activities to enable sharing between apps. An Android app has a manifest file (an XML config file similar to Apple’s &lt;code&gt;Info.plist&lt;/code&gt;) in which it can list all its activities and how they can be activated from other apps.&lt;/p&gt;

&lt;h2&gt;Intents&lt;/h2&gt;

&lt;p&gt;The launch of an activity is done with so-called &lt;a href=&quot;http://developer.android.com/guide/topics/intents/intents-filters.html&quot;&gt;Intents&lt;/a&gt;. Intent is just another name for a message data structure that contains an operation to be performed by the system. One of the several possible message types is to start an activity. Activities to be launched can be either named directly (if you want to launch a specific activity in a specific app) or the intent can specify the predefined action &lt;a href=&quot;http://developer.android.com/training/sharing/send.html&quot;&gt;&lt;code&gt;ACTION_SEND&lt;/code&gt;&lt;/a&gt; to indicate that it wants to send data from one activity to another. Based on the data and its type that your app passes to the intent object, the OS will then identify all activities from all apps that can handle this type of data&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; and present them to the user in a list.&lt;/p&gt;

&lt;p&gt;When the user selects the activity/app he wants to use, the system launches the activity and passes it the data contained in the intent object. By default, activities do not report anything back to their caller. A backchannel from the launched to the launching activity can optionally be established by using the &lt;a href=&quot;http://developer.android.com/reference/android/app/Activity.html#startActivityForResult(android.content.Intent,%20int)&quot;&gt;&lt;code&gt;startActivityForResult()&lt;/code&gt;&lt;/a&gt; method, however.&lt;/p&gt;

&lt;h1&gt;Windows 8&lt;/h1&gt;

&lt;p&gt;I have chosen to take a look at the Windows 8 APIs rather than Windows Phone 7 here for two reasons. Firstly, Windows Phone 7 has no generic content sharing API. There do exist classes to &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.phone.tasks.sharelinktask(v=vs.92).aspx&quot;&gt;share links&lt;/a&gt; and &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.phone.tasks.sharestatustask(v=vs.92).aspx&quot;&gt;status messages&lt;/a&gt; on selected social networks but the list of sharing services does not seem to be extensible. A feature called “app-to-app communication” (whatever that means) is &lt;a href=&quot;http://pocketnow.com/windows-phone/exclusive-windows-phone-8-detailed&quot;&gt;rumored to be part of Windows Phone 8&lt;/a&gt;. Secondly, it seems at least possible (if not probable) that &lt;a href=&quot;http://www.theverge.com/2011/11/15/2564399/microsoft-bringing-windows-8-to-phones&quot;&gt;Windows Phone will soon be based on the Windows 8 platform&lt;/a&gt; and Microsoft’s new &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/apps/hh464942.aspx&quot;&gt;WinRT API&lt;/a&gt; will also be relevant for Windows Phone development.&lt;/p&gt;

&lt;h2&gt;Charms&lt;/h2&gt;

&lt;div class=&quot;with-caption align-right&quot; style=&quot;width:244px;&quot;&gt;
  &lt;p&gt;&lt;img src=&quot;/media/windows-8-metro-share-contract.png&quot; alt=&quot;Windows 8 displaying the Share action in the Charms bar.&quot;&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;Windows 8 displaying the Share action in the Charms bar.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;In the Windows 8 Metro interface, users can swipe from the screen edge to display the so-called &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/apps/br211373.aspx&quot;&gt;Charms bar&lt;/a&gt;, regardless of the app they are currently using. The Charms bar contains buttons for several often-used actions, such as going back to the start screen or accessing the current app’s settings. Other charms include Search (&lt;q&gt;to search for content from your app, other participating apps, or the file system&lt;/q&gt;) and Share (&lt;q&gt;to share content from your app with other users, web services, or other apps&lt;/q&gt;).&lt;/p&gt;

&lt;h2&gt;Contracts&lt;/h2&gt;

&lt;p&gt;Each of those charms is related to and governed by a so-called &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/apps/hh464906.aspx&quot;&gt;Contract&lt;/a&gt;. The documentation describes contracts as&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;agreements between Windows and one or more Metro style apps, called contract participants, to support some kind of user interaction. There is a contract for each type of interaction, like playing music from an application to a connected stereo, and the contract specifies the types of capabilities the participant has. For example, Windows lets users share content from one application to another. The application that shares content out supports a source contract by meeting specific requirements while the application that receives the shared content supports a target contract by meeting a different set of requirements. Every application that participates in the sharing contract can be confident that the sharing workflow is completely supported, end-to-end.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Similar to Android, Metro apps must declare the contracts they support. They can do this either by specifying them in the app’s manifest file or even dynamically at runtime. In the current developer preview release, Windows 8 supports &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/apps/hh464906.aspx&quot;&gt;five contracts&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search:&lt;/strong&gt; to search an app’s locally stored content or have an app control a search query that goes out to the web for searching. For example, a YouTube app could offer YouTube online search through this contract.&lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Sharing:&lt;/strong&gt; to share content from your app with another app or web service.&lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Play To:&lt;/strong&gt; to play music and video from an app on other connected devices that support the &lt;a href=&quot;http://en.wikipedia.org/wiki/Digital_Living_Network_Alliance&quot;&gt;DLNA&lt;/a&gt; standard. This looks similar to Apple’s &lt;a href=&quot;http://en.wikipedia.org/wiki/AirPlay&quot;&gt;AirPlay&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Settings:&lt;/strong&gt; to provide access to an app’s settings.&lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;App to App Picking:&lt;/strong&gt; to let an app directly pick files from another app. This looks like a very elegant solution to the problem that, when all apps are sandboxed, there does not exist a shared folder on the file system that users could use to exchange files between apps. With this contract, a Dropbox client for Windows Metro could offer the user the option to open files that are in the Dropbox directly from within another app, for example.&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;The Sharing Contract&lt;/h2&gt;

&lt;p&gt;Let’s have a look at how content sharing works with the Sharing contract. To make this work, the source application must first declare to the OS that it supports the role of acting as a &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/apps/hh465261.aspx&quot;&gt;sharing source&lt;/a&gt;. The application listens for an event that signifies to the app that the user activated the Share charm. In response to this event, it will then create a &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/apps/windows.applicationmodel.datatransfer.datapackage.aspx&quot;&gt;&lt;code&gt;DataPackage&lt;/code&gt;&lt;/a&gt; object that contains the content to be shared. DataPackages are very flexible: they can contain any combination of plain text, URLs, HTML, rich text, images, files or arbitrary binary data. The source application passes the packaged data on to the operating system.&lt;/p&gt;

&lt;p&gt;If large amounts of data should be shared, or if the format of the data is not yet determined because it is up to the target application to select one of multiple supported formats, the source application can also set up a sharing delegate that only prepares and packages the data once it has been requested by the target application.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The OS will now present the user with a list of apps that can handle the shared content. Again, the set of suitable apps is determined by parsing the manifest files of all installed apps. Valid apps are those that support the “Receive Shared Content” contract and have indicated that they can handle the data types the OS is currently dealing with.&lt;/p&gt;

&lt;p&gt;When the user selects an app from the list, the OS will activate the target app and pass it the shared &lt;code&gt;DataPackage&lt;/code&gt; object. The app is now expected to deal with the shared data. Depending on the size of the data, it has the option to do this synchronously or asynchronously in the background, thereby letting the user return to the source application before the actual processing is complete. The target app is free in its decision whether to display its own UI or not. When the operation is completed, the SDK provides APIs for the target app to report success or failure to the source app.&lt;/p&gt;

&lt;h1&gt;Learnings for iOS&lt;/h1&gt;

&lt;p&gt;Comparing the two approaches, Android’s system of intents and activities seems extremely flexible. It cannot only be used for sharing content between apps but also for sharing functionality. For example, a Twitter client on Android can seamlessly launch a web browser activity to display a web page, and the user can always go back to the tweet list by using the device’s back button. For a Twitter app on iOS, launching the browser to read an article would result in a very bad user experience.&lt;/p&gt;

&lt;p&gt;Microsoft’s concept of contracts seems to be better suited to iOS’s application model. Rather than directly accessing parts of an app (activities/view controllers), the target application of a sharing charm is launched normally and has to decide upon activation how to react to the sharing operation in process. This is very similar to how iOS deals with push notifications or app launches through a URL scheme.&lt;/p&gt;

&lt;p&gt;So far, Apple’s approach to content sharing in iOS seems to be offering piecemeal solutions. Over the years, Apple has gradually added system-defined view controllers for system-defined actions: as of iOS 5, apps can share stuff via &lt;a href=&quot;https://developer.apple.com/library/ios/#documentation/MessageUI/Reference/MFMailComposeViewController_class/Reference/Reference.html&quot;&gt;e-mail&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/library/ios/#documentation/MessageUI/Reference/MFMessageComposeViewController_class/Reference/Reference.html&quot;&gt;SMS&lt;/a&gt; or &lt;a href=&quot;https://developer.apple.com/library/ios/#documentation/Twitter/Reference/TWTweetSheetViewControllerClassRef/Reference/Reference.html&quot;&gt;Twitter&lt;/a&gt; using the built-in view controllers. In addition, apps have write access to the device’s photo library and can sort of share images that way.&lt;/p&gt;

&lt;h2&gt;We Need a Generic Sharing API&lt;/h2&gt;

&lt;p&gt;What’s missing is the generic design. Even if we will see &lt;code&gt;FBFacebookShareViewController&lt;/code&gt; and &lt;code&gt;IGInstagramSharePhotoViewController&lt;/code&gt; in the next iOS release, Apple will never be able (or willing) to support a large enough number of sharing services and apps. And interaction between apps via custom URL schemes as currently implemented in iOS also doesn’t cut it: since a source application would need to know about and implement the URL schemes of all potential target apps, this idea just doesn’t scale to 500,000 apps.&lt;/p&gt;

&lt;p&gt;A generic sharing API like the ones described above would solve tons of developer issues at one go. For instance, Instapaper developer Marco Arment has been complaining for a long time that &lt;a href=&quot;http://www.marco.org/2010/10/10/an-open-enhancement-request-to-the-mobile-safari-team&quot;&gt;requiring your users to install a bookmarklet in Mobile Safari sucks&lt;/a&gt;. If both Safari and the Instapaper app supported the sharing of URLs and/or web page content, this problem would be solved. Similarly, developers of Twitter apps would no longer have to talk to the Instapaper API directly if they could just share a link with the Instapaper app on the device.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;My dream feature for iOS 6 is a combination of the share sheets introduced in Mountain Lion (for displaying the available sharing options) and an implementation similar to Windows 8 contracts that allow for both silent (non-invasive, no UI) and more explicit (with a custom UI like the current mail or tweet compose view controllers) content sharing between apps. If you agree, please &lt;a href=&quot;http://bugreport.apple.com/&quot;&gt;file an enhancement request with Apple&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;Activities are usually presented covering the entire screen but this is not a requirement. An activity can also be displayed in a floating window or embedded inside of another activity. These features will remind iOS developers of &lt;a href=&quot;https://developer.apple.com/library/ios/#documentation/uikit/reference/UIPopoverController_class/Reference/Reference.html&quot;&gt;popover views&lt;/a&gt; on the iPad and &lt;a href=&quot;https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/AboutViewControllers/AboutViewControllers.html#//apple_ref/doc/uid/TP40007457-CH112-SW17&quot;&gt;container view controllers&lt;/a&gt; in iOS 5.&lt;a href=&quot;#fnref:1&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;Identified by the data’s MIME type. The matching of data types and activities is performed based on the information in every app’s manifest file where the developer can list the data types any of their activities can deal with.&lt;a href=&quot;#fnref:2&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot;&gt;
      &lt;p&gt;OS X uses the same mechanism for drag and drop operations.&lt;a href=&quot;#fnref:3&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot;&gt;
      &lt;p&gt;Especially if the sharing process could optionally be non-interactive so as to make it a one-tap operation. Windows 8 supports the innovative concept of &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/apps/windows.applicationmodel.datatransfer.sharetarget.quicklink.aspx&quot;&gt;QuickLinks&lt;/a&gt; where the target app can return a link that corresponds to the last sharing operation that the OS can then display in the Charms bar.&lt;a href=&quot;#fnref:4&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2012/02/share-sheets-only-half-way-there/</id>
    <title>Share Sheets: Only Half Way There</title>
    <published>2012-02-17T20:45:00Z</published>
    <updated>2012-02-20T20:15:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2012/02/share-sheets-only-half-way-there/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2012/02/share-sheets-only-half-way-there/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;When I read the news about OS X Mountain Lion yesterday, one of the most exciting new features was the concept of &lt;a href=&quot;http://www.apple.com/macosx/mountain-lion/features.html#sharesheet&quot;&gt;Share Sheets&lt;/a&gt;, the system-wide component that enables any app to let users easily share content with a number of popular OS and web services. &lt;/p&gt;

&lt;h1&gt;Not Extensible by Third-Party Apps&lt;/h1&gt;

&lt;p&gt;At the time, I assumed that this service was completely open to third party apps. Apps should not only be able to &lt;em&gt;show&lt;/em&gt; the system-wide sharing UI; they should also be allowed to offer &lt;em&gt;additional&lt;/em&gt; sharing services that would then be displayed among the built-in options by any other app that supported share sheets.&lt;/p&gt;

&lt;p&gt;This seems to be a sensible idea, after all. Different users have different sharing preferences and while the list of built-in services includes some high-profile sites like Twitter, Flickr and Vimeo, it is hardly complete (not to mention the dozens of new services that spring up every year, like Instagram).&lt;/p&gt;

&lt;p&gt;Sadly, according to &lt;a href=&quot;http://www.theverge.com/2012/2/16/2801047/mac-os-x-10-8-mountain-lion-preview-photos-video&quot;&gt;Nilay Patel’s Mountain Lion preview for The Verge&lt;/a&gt;, this is not the case:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;There’s an API that lets developers add share buttons to third party apps, but there’s no way to add additional services — a pity, since Facebook and YouTube are notable omissions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On OS X, this limitation is actually not that big a deal. In fact, OS X makes manual sharing between one app and another or between an app and the web so easy that the whole idea of a system-wide UI component for sharing seems almost superfluous. I can just as quickly copy and paste or drag and drop a URL from the browser to the Twitter app as I can tweet about it using a share sheet.&lt;/p&gt;

&lt;p&gt;What I am worried about is what this means for iOS.&lt;/p&gt;

&lt;h1&gt;A Missed Opportunity for iOS?&lt;/h1&gt;

&lt;p&gt;On iOS, sharing content between apps is hard. Yes, there is copy and paste but repeatedly switching between apps still takes a lot of effort. And sharing content via URL schemes only works if the sending app explicitly supports the receiving app’s format, which is a problem whose solution just doesn’t scale.&lt;/p&gt;

&lt;p&gt;Moreover, iOS could soon be at a major disadvantage compared to its competitors when it comes to sharing content. Both Android (with its existing system of &lt;a href=&quot;http://developer.android.com/training/sharing/send.html&quot;&gt;Activities and Intents&lt;/a&gt;) and soon Windows (Phone) (with &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/apps/hh464906.aspx&quot;&gt;Contracts&lt;/a&gt; coming in Windows 8) offer a system-wide solution for apps to interact with each other. Meanwhile, iOS only offers built-in sharing via e-mail, SMS/iMessage and Twitter.&lt;/p&gt;

&lt;h1&gt;Extensible Share Sheets in iOS 6?&lt;/h1&gt;

&lt;p&gt;Imagine if Apple not only ported the existing share sheets API to iOS 6 but also added third-party extensibility along the way. Any app, be it from Apple or a third-party developer, could announce via its &lt;code&gt;Info.plist&lt;/code&gt; the types of content (text, URLs, photos, videos, etc.) it understands. And every app that had something to share would, when the user taps its share button, ask the OS to display a list of apps that can deal with the current content. The system’s sharing service would automatically launch the app the user selected and ask it to display its special sharing view controller&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Any app that implemented share sheets would automatically support any other app that can deal with the same content type. You could send URLs from Safari directly to the Instapaper app, without having to install a bookmarklet. A photo editing app would support uploading to any photo service without having to implement dozens of APIs&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. You could post your high score from any game to your social network of choice. The possibilities are endless.&lt;/p&gt;

&lt;p&gt;I can only hope Apple will still do this for iOS 6. Seeing only part of it in Mountain Lion makes me pessimistic.&lt;/p&gt;

&lt;p class=&quot;update&quot;&gt;&lt;strong&gt;Update February 20, 2012:&lt;/strong&gt; I wrote a follow-up to this article: &lt;a href=&quot;/blog/2012/02/what-ios-should-learn-from-android-and-windows-8/&quot;&gt;What iOS Should Learn from Android and Windows 8&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;Optionally, an app could perhaps act to share things silently without displaying its own UI. In that case, the sharing service could just call a special block of code in the receiving app’s executable that automatically uploads the content. In such a scenario, sending a URL to Instapaper would be even more seamless.&lt;a href=&quot;#fnref:1&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;And the companies that run the photo services could concentrate on an app that excels in uploading new content and browsing the existing site rather than investing in photo editing and filtering capabilities that other, specialized apps could do better.&lt;a href=&quot;#fnref:2&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2012/02/app-launch-sequence-ios-revisited/</id>
    <title>Revisiting the App Launch Sequence on iOS</title>
    <published>2012-02-09T20:20:00Z</published>
    <updated>2012-02-09T20:20:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2012/02/app-launch-sequence-ios-revisited/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2012/02/app-launch-sequence-ios-revisited/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;In June 2011, I blogged about &lt;a href=&quot;/blog/2011/06/app-launch-sequence-ios/&quot;&gt;the App Launch Sequence on iOS&lt;/a&gt; for the first time, illustrating what really happens under the hood between the launch of an iOS app and the &lt;a href=&quot;https://developer.apple.com/library/IOs/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/Reference/Reference.html#//apple_ref/doc/uid/TP40006786-CH3-SW18&quot;&gt;&lt;code&gt;application:didFinishLaunchingWithOptions:&lt;/code&gt;&lt;/a&gt; method.&lt;/p&gt;

&lt;p&gt;Since that time, Apple has revised the default launch sequence in their iOS app project templates, so it is time for an update to the original post.&lt;/p&gt;

&lt;h1&gt;Flowchart&lt;/h1&gt;

&lt;div class=&quot;with-caption&quot; style=&quot;width:700px&quot;&gt;
  &lt;p&gt;&lt;a href=&quot;/media/xcode-4-2-app-launch-sequence.png&quot; class=&quot;img-link&quot;&gt;&lt;img src=&quot;/media/xcode-4-2-app-launch-sequence-700px.png&quot; alt=&quot;App Launch Sequence as of Xcode 4.2 (without Storyboarding)&quot;&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;Flowchart of the default app launch sequence in iOS as of Xcode 4.2 for a non-storyboarded app. Feel free to share this image under a &lt;a href=&quot;http://creativecommons.org/licenses/by/3.0/&quot;&gt;Creative Commons Attribution license&lt;/a&gt; (CC-BY). In a storyboarded app, &lt;code&gt;UIApplicationMain()&lt;/code&gt; would additionally initiate the loading of the app’s main storyboard file, which in turn would create the window and initial view controller.&lt;/p&gt;
&lt;/div&gt;

&lt;h1&gt;Changes to &lt;code&gt;main()&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Let’s have a look at the changes to the &lt;code&gt;main()&lt;/code&gt; function, which still is the starting point for our app. The function now looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl kwb&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hl kwb&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;argv&lt;span class=&quot;hl opt&quot;&gt;[])&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl kwc&quot;&gt;@autoreleasepool&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;UIApplicationMain&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;argc&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; argv&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;NSStringFromClass&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;([&lt;/span&gt;AppDelegate &lt;span class=&quot;hl kwa&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;]));&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;main()&lt;/code&gt; uses the new &lt;code&gt;@autoreleasepool { }&lt;/code&gt; syntax introduced with LLVM 3.0, but that change doesn’t concern the app’s launch sequence. More importantly, the call to &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/Reference/reference.html#//apple_ref/doc/uid/TP40006894-CH3-SW7&quot;&gt;&lt;code&gt;UIApplicationMain()&lt;/code&gt;&lt;/a&gt; changed from &lt;code&gt;UIApplicationMain(argc, argv, nil, nil);&lt;/code&gt; to the one shown above. Note the change in the fourth argument.&lt;/p&gt;

&lt;p&gt;Looking at &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/Reference/reference.html#//apple_ref/doc/uid/TP40006894-CH3-SW7&quot;&gt;the documentation&lt;/a&gt;, we learn that the fourth argument to &lt;code&gt;UIApplicationMain()&lt;/code&gt; specifies&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The name of the class from which the application delegate is instantiated. … Specify &lt;code&gt;nil&lt;/code&gt; if you load the delegate object from your application’s main nib file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So apparently our app delegate, which was previously created with Interface Builder inside &lt;code&gt;MainWindow.xib&lt;/code&gt;, is now created directly by the &lt;code&gt;UIApplicationMain()&lt;/code&gt; function.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; In fact, there isn’t even a &lt;code&gt;MainWindow.xib&lt;/code&gt; file anymore in our project!&lt;/p&gt;

&lt;h1&gt;No MainWindow.xib&lt;/h1&gt;

&lt;p&gt;Before Xcode 4.2, all default project templates did create a &lt;code&gt;MainWindow.xib&lt;/code&gt; file. Because this file was specified in the app’s &lt;code&gt;Info.plist&lt;/code&gt; as the main NIB file, the &lt;code&gt;UIApplicationMain()&lt;/code&gt; function would load it automatically right after it had created the &lt;a href=&quot;https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/occ/cl/UIApplication&quot;&gt;&lt;code&gt;UIApplication&lt;/code&gt;&lt;/a&gt; instance for the app.&lt;/p&gt;

&lt;p&gt;It was then inside the NIB file that both the application delegate object and the app’s main window were created and wired together via outlets. More often than not, &lt;code&gt;MainWindow.xib&lt;/code&gt; would also include the app’s root view controller, already connected to a custom outlet in the application delegate class and the window’s &lt;code&gt;rootViewController&lt;/code&gt; outlet.&lt;/p&gt;

&lt;p&gt;With so much work done inside the main NIB file, the default &lt;code&gt;application:didFinishLaunchingWithOptions:&lt;/code&gt; method could be kept almost empty. All it had to do was bring the window on screen:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;application&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UIApplication &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;application didFinishLaunchingWithOptions&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;NSDictionary &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;launchOptions
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl slc&quot;&gt;// Override point for customization after application launch.&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.window makeKeyAndVisible&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; YES&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For Xcode 4.2 and later, Apple has decided to remove the main NIB file from the iOS project templates. The immediate reason for this change was most likely the introduction of &lt;a href=&quot;https://developer.apple.com/library/ios/#releasenotes/Miscellaneous/RN-AdoptingStoryboards/_index.html&quot;&gt;storyboarding&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Storyboards are based around view controllers, not views or windows. Sticking to the concept of a main NIB file for a storyboard-based app would make no sense (and is impossible since the &lt;code&gt;Info.plist&lt;/code&gt; keys &lt;code&gt;NSMainNibFile&lt;/code&gt; and &lt;code&gt;UIMainStoryboardFile&lt;/code&gt; &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html#//apple_ref/doc/uid/TP40009252-SW9&quot;&gt;are mutually exclusive&lt;/a&gt;). And abandoning the main NIB file only for storyboard-based apps but keeping it for others would lead to project templates differ from each other more than necessary.&lt;/p&gt;

&lt;h1&gt;More Work To Do in &lt;code&gt;application:didFinishLaunchingWithOptions:&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;With the main NIB file gone, the tasks that were performed in the NIB file must now move elsewhere. We have already seen that &lt;code&gt;UIApplicationMain()&lt;/code&gt; takes over one of them: the creation of our application delegate. Since the function now has control over both the &lt;code&gt;UIApplication&lt;/code&gt; instance and its delegate, we can also safely assume that it will assign the delegate to the application instance.&lt;/p&gt;

&lt;p&gt;At this stage, the &lt;code&gt;application:didFinishLaunchingWithOptions:&lt;/code&gt; message will be sent. Since nobody has created a window or view controller yet, the method now performs these tasks in code, at least for an app that is not storyboard-based:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;application&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UIApplication &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;application didFinishLaunchingWithOptions&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;NSDictionary &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;launchOptions
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.window &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;UIWindow alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithFrame&lt;span class=&quot;hl opt&quot;&gt;:[[&lt;/span&gt;UIScreen mainScreen&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; bounds&lt;span class=&quot;hl opt&quot;&gt;]];&lt;/span&gt;
    &lt;span class=&quot;hl slc&quot;&gt;// Override point for customization after application launch.&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.viewController &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;ViewController alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithNibName&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;ViewController&quot;&lt;/span&gt; bundle&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.window.rootViewController &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.viewController&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.window makeKeyAndVisible&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; YES&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If your app uses storyboarding (by specifying a &lt;code&gt;UIMainStoryboardFile&lt;/code&gt; in &lt;code&gt;Info.plist&lt;/code&gt;), the app will automatically load the main storyboard file at launch, just like the main NIB file. It will also create a window and place the storyboard’s initial view controller inside it, and bring the window on screen. Therefore, there is nothing left to do for us in &lt;code&gt;application:didFinishLaunchingWithOptions:&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;application&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UIApplication &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;application didFinishLaunchingWithOptions&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;NSDictionary &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;launchOptions
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl slc&quot;&gt;// Override point for customization after application launch.&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; YES&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;A Litte More Code But Clearer&lt;/h1&gt;

&lt;p&gt;Initializing our (non-storyboard) app now takes a few more lines of code than before, but I think this change made the application launch sequence a lot clearer than before. I know many iOS developers who have had problems understanding the launch process because the role the main NIB file played was not clear to them.&lt;/p&gt;

&lt;p&gt;Im a generally a big proponent of using NIB files/storyboards but in some cases they can confuse more than they help.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;The syntax &lt;code&gt;NSStringFromClass([AppDelegate class])&lt;/code&gt; might seem a little strange. Why did Apple not just use a plain string @”AppDelegate” here? The result would be the same. They probably did it the more complicated way to simplify refactoring: if you want to rename the &lt;code&gt;AppDelegate&lt;/code&gt; class, the built-in refactoring tool would detect its use in &lt;code&gt;main()&lt;/code&gt; and rename it there as well. That would obviously not work if it were just a string.&lt;a href=&quot;#fnref:1&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2012/02/cgpath-hit-testing/</id>
    <title>CGPath Hit Testing</title>
    <published>2012-02-03T18:00:00Z</published>
    <updated>2012-02-03T18:00:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2012/02/cgpath-hit-testing/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2012/02/cgpath-hit-testing/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;In OS X 10.7 and iOS 5.0, Apple added an inconspicuous new function named &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/graphicsimaging/Reference/CGPath/Reference/reference.html#//apple_ref/doc/uid/TP30000959-CH1g-SW6&quot;&gt;&lt;code&gt;CGPathCreateCopyByStrokingPath()&lt;/code&gt;&lt;/a&gt; to the Core Graphics framework. As the documentation says and the name implies, this function&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;[c]reates a stroked copy of another path. … The new path is created so that filling the new path draws the same pixels as stroking the original path.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This may sound like a pretty obscure use case that is rarely needed but in fact, this functionality can be extremely useful for a number of problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Stroking a path with fancy graphics.&lt;/strong&gt; You can normally only stroke a path with a single color. If you want to do something fancier like, say, draw a gradient, &lt;code&gt;CGPathCreateCopyByStrokingPath()&lt;/code&gt; lets you convert the area that would be stroked into a new path. You can then use this new path as the clipping path for the gradient you want to draw.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Stroking a stroke.&lt;/strong&gt; If you want to draw a stroke around a path’s stroke, use &lt;code&gt;CGPathCreateCopyByStrokingPath()&lt;/code&gt; to create a new path from the original path’s stroke, and stroke the new path.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Hit testing.&lt;/strong&gt; The &lt;code&gt;CGPath&lt;/code&gt; APIs can only help you if you want to hit test the for &lt;em&gt;interior&lt;/em&gt; of a path, not if your hit target is the path’s contour. Since &lt;code&gt;CGPathCreateCopyByStrokingPath()&lt;/code&gt; can convert the countour into a new path’s interior, it can help with this problem, too.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;In this article, I want to show you an example app that covers the second and third of these problems.&lt;/p&gt;

&lt;h1&gt;The Demo App&lt;/h1&gt;

&lt;p&gt;Imagine you have a vector drawing app that lets the user draw both regular shapes like rectangles and ellipses and “irregular” ones like freeform paths and bezier curves. In your app, you represent the shapes that make up the current document with an array of &lt;code&gt;CGPath&lt;/code&gt; objects (or an array of &lt;a href=&quot;https://developer.apple.com/library/IOs/#documentation/UIKit/Reference/UIBezierPath_class/Reference/Reference.html&quot;&gt;&lt;code&gt;UIBezierPath&lt;/code&gt;&lt;/a&gt; (iOS)/&lt;a href=&quot;https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSBezierPath_Class/Reference/Reference.html&quot;&gt;&lt;code&gt;NSBezierPath&lt;/code&gt;&lt;/a&gt; (Mac) objects, which themselves wrap a &lt;code&gt;CGPath&lt;/code&gt; – the difference is not important for this discussion).&lt;/p&gt;

&lt;p&gt;The user can add new (random) shapes to the view, select shapes by tapping on their outline, drag shapes across the view and delete a selected shape. Watch this short video for an overview:&lt;/p&gt;

&lt;div class=&quot;with-caption&quot; style=&quot;width:698px;&quot;&gt;
  &lt;video width=&quot;698&quot; height=&quot;546&quot; controls=&quot;controls&quot;&gt;&lt;source src=&quot;/media/CGPathHitTestingDemoApp.m4v&quot; type=&quot;video/mp4&quot;&gt;&lt;/source&gt;&lt;/video&gt;&lt;p class=&quot;caption&quot;&gt;The sample iPad app. &lt;a href=&quot;/media/CGPathHitTestingDemoApp.m4v&quot;&gt;Download the video (H.264, 2 MB)&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;The source code for the demo app is &lt;a href=&quot;https://github.com/ole/CGPathHitTesting&quot;&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;Hit Testing with &lt;code&gt;CGPathCreateCopyByStrokingPath&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;You need to provide the functionality that existing shapes can be edited at a later time and for that, you need a way for the user to select shapes by tapping on them. To help you with this, the &lt;code&gt;CGPath&lt;/code&gt; API provides the &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/graphicsimaging/Reference/CGPath/Reference/reference.html#//apple_ref/doc/uid/TP30000959-CH1g-CJBGIGEF&quot;&gt;&lt;code&gt;CGPathContainsPoint()&lt;/code&gt;&lt;/a&gt; function&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, which&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;[c]hecks whether a point is contained in a graphics path. … A point is contained in a path if it would be inside the painted region when the path is filled.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This function is helpful if you want to hit test on the entire region the path covers. As such, &lt;code&gt;CGPathContainsPoint()&lt;/code&gt; doesn’t work with unclosed paths because those don’t have an interior that would be filled. The method of selecting shapes by tapping anywhere in their interior can also be problematic from a user interface perspective? What if the user taps at a location where multiple shapes overlap? What shape should the app select?&lt;/p&gt;

&lt;p&gt;Such ambiguities can be minimized if shape selection only works on the shape’s outline and not its entire interior.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; And here is where &lt;code&gt;CGPathCreateCopyByStrokingPath()&lt;/code&gt; comes into play: whenever the user creates or modifies a shape, we call &lt;code&gt;CGPathCreateCopyByStrokingPath()&lt;/code&gt; on it to create a mirroring &lt;code&gt;tapTarget&lt;/code&gt; object that only covers the stroked area of the path (ensuring a certain minimum width to make the tap target big enough). When the user taps on the screen, we iterate over the tap targets rather than the actual shapes, now using &lt;code&gt;CGPathContainsPoint()&lt;/code&gt; on the area that would be filled by the shape’s outline, to determine which shape was selected. In the sample app, the &lt;code&gt;Shape&lt;/code&gt; class contains a method named &lt;code&gt;tapTargetForPath:&lt;/code&gt; that generates such a tap target for a given &lt;code&gt;path&lt;/code&gt; object (which is a &lt;code&gt;UIBezierPath&lt;/code&gt; in this instance). Note that I am using a minimum width of 35 points for the tap target, regardless of the path’s &lt;code&gt;lineWidth&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;UIBezierPath &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;tapTargetForPath&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UIBezierPath &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;path
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;path &lt;span class=&quot;hl opt&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
        &lt;span class=&quot;hl kwa&quot;&gt;return nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    
    CGPathRef tapTargetPath &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;CGPathCreateCopyByStrokingPath&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;path.CGPath&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; NULL&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;fmaxf&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;35.0&lt;/span&gt;f&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; path.lineWidth&lt;span class=&quot;hl opt&quot;&gt;),&lt;/span&gt; path.lineCapStyle&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; path.lineJoinStyle&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; path.miterLimit&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;tapTargetPath &lt;span class=&quot;hl opt&quot;&gt;==&lt;/span&gt; NULL&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
        &lt;span class=&quot;hl kwa&quot;&gt;return nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    
    UIBezierPath &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;tapTarget &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;UIBezierPath bezierPathWithCGPath&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;tapTargetPath&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwd&quot;&gt;CGPathRelease&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;tapTargetPath&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; tapTarget&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;containsPoint:&lt;/code&gt; method in the &lt;code&gt;Shape&lt;/code&gt; class then uses its &lt;code&gt;tapTarget&lt;/code&gt; (rather than its &lt;code&gt;path&lt;/code&gt;) to test whether it contains a given point or not. The result is that it returns &lt;code&gt;YES&lt;/code&gt; only for points on the path’s outline (again, with a minimum width of 35 points).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;containsPoint&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;CGPoint&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;point
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.tapTarget containsPoint&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;point&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now the hit testing code in the view controller is trivial. We just enumerate over all existing shapes and return the index of the first shape whose tap target matches the given location:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;NSUInteger&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;hitTest&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;CGPoint&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;point
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    __block NSUInteger hitShapeIndex &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; NSNotFound&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.shapes enumerateObjectsWithOptions&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSEnumerationReverse usingBlock&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;^&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;id&lt;/span&gt; shape&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; NSUInteger idx&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;BOOL&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;stop&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
        &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;([&lt;/span&gt;shape containsPoint&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;point&lt;span class=&quot;hl opt&quot;&gt;]) {&lt;/span&gt;
            hitShapeIndex &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; idx&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;stop &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; YES&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; hitShapeIndex&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;Drawing a Selection Outline with &lt;code&gt;CGPathCreateCopyByStrokingPath&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;We use the &lt;code&gt;hitTest:&lt;/code&gt; method to determine which shape the user has selected. In the demo app, she can drag the selected shape to another location or opt to delete it. To show the user which shape, if any, is currently selected, we should highlight the selected shape in some way. Let’s do that with a dashed outline.&lt;/p&gt;

&lt;p&gt;I want the dashed outline to appear &lt;em&gt;around&lt;/em&gt; the shape’s regular outline, so in &lt;code&gt;CGPath&lt;/code&gt; parlance, I have to stroke the path’s stroke. As mentioned above, we can do that with our new favorite Core Graphics function. In our &lt;code&gt;drawRect:&lt;/code&gt; method, we check whether the shape we are currently drawing is selected, and if it is, we use &lt;code&gt;CGPathCreateCopyByStrokingPath()&lt;/code&gt; to create a new path of the shape’s outline and then &lt;code&gt;stroke&lt;/code&gt; this copy with a dashed line:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;drawRect&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;CGRect&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;rect
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    NSUInteger numberOfShapes &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.dataSource numberOfShapesInDrawingView&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    NSUInteger indexOfSelectedShape &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; NSNotFound&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.dataSource respondsToSelector&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwc&quot;&gt;@selector&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;indexOfSelectedShapeInDrawingView&lt;span class=&quot;hl opt&quot;&gt;:)]) {&lt;/span&gt;
        indexOfSelectedShape &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.dataSource indexOfSelectedShapeInDrawingView&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;hl kwa&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;NSUInteger shapeIndex &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl num&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt; shapeIndex &lt;span class=&quot;hl opt&quot;&gt;&amp;lt;&lt;/span&gt; numberOfShapes&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt; shapeIndex&lt;span class=&quot;hl opt&quot;&gt;++)&lt;/span&gt; 
    &lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
        UIBezierPath &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;path &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.dataSource drawingView&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; pathForShapeAtIndex&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;shapeIndex&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwd&quot;&gt;CGRectIntersectsRect&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;rect&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;CGRectInset&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;path.bounds&lt;span class=&quot;hl opt&quot;&gt;, -(&lt;/span&gt;path.lineWidth &lt;span class=&quot;hl opt&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl num&quot;&gt;1.0&lt;/span&gt;f&lt;span class=&quot;hl opt&quot;&gt;), -(&lt;/span&gt;path.lineWidth &lt;span class=&quot;hl opt&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl num&quot;&gt;1.0&lt;/span&gt;f&lt;span class=&quot;hl opt&quot;&gt;))))&lt;/span&gt; 
        &lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
            UIColor &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;lineColor &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.dataSource drawingView&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; lineColorForShapeAtIndex&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;shapeIndex&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
            &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;lineColor setStroke&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
            &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;path stroke&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;

            &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;shapeIndex &lt;span class=&quot;hl opt&quot;&gt;==&lt;/span&gt; indexOfSelectedShape&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
                UIBezierPath &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;pathCopy &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;path copy&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
                CGPathRef cgPathSelectionRect &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;CGPathCreateCopyByStrokingPath&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;pathCopy.CGPath&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; NULL&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; pathCopy.lineWidth&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; pathCopy.lineCapStyle&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; pathCopy.lineJoinStyle&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; pathCopy.miterLimit&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
                UIBezierPath &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;selectionRect &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;UIBezierPath bezierPathWithCGPath&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;cgPathSelectionRect&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
                &lt;span class=&quot;hl kwd&quot;&gt;CGPathRelease&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;cgPathSelectionRect&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;

                CGFloat dashStyle&lt;span class=&quot;hl opt&quot;&gt;[] = {&lt;/span&gt; &lt;span class=&quot;hl num&quot;&gt;5.0&lt;/span&gt;f&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;hl num&quot;&gt;5.0&lt;/span&gt;f &lt;span class=&quot;hl opt&quot;&gt;};&lt;/span&gt;
                &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;selectionRect setLineDash&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;dashStyle count&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;2&lt;/span&gt; phase&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
                &lt;span class=&quot;hl opt&quot;&gt;[[&lt;/span&gt;UIColor blackColor&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; setStroke&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
                &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;selectionRect stroke&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
            &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that we are using the delegation pattern to have our view ask its data source for the shapes it should draw, their colors, and which one is the currently selected shape. We then take care to only draw a shape if its bounding box intersects with the rectangle we actually need to redraw to make drawing more efficient. The drawing of the selection outline takes place inside the &lt;code&gt;if (shapeIndex == indexOfSelectedShape) { … }&lt;/code&gt; block. Note that the first line in the block (&lt;code&gt;UIBezierPath *pathCopy = [path copy];&lt;/code&gt;) should not be necessary but I found it to be so to make sure that &lt;code&gt;pathCopy&lt;/code&gt; always reflects the latest changes to the path&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h1&gt;Replicating &lt;code&gt;CGPathCreateCopyByStrokingPath&lt;/code&gt; in iOS 4 and Mac OS X 10.6&lt;/h1&gt;

&lt;p&gt;Since OS X 10.4 (and iOS 2.0), Core Graphics included the function &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/graphicsimaging/reference/CGContext/Reference/reference.html#//apple_ref/doc/uid/TP30000950-CH1g-BCIICCBI&quot;&gt;&lt;code&gt;CGContextReplacePathWithStrokedPath()&lt;/code&gt;&lt;/a&gt;. It essentially works the same way &lt;code&gt;CGPathCreateCopyByStrokingPath()&lt;/code&gt; – with the large downside that it requires a graphics context to work on, which is usually not the case when doing hit testing. But it remains the best workaround I know of if you need to support older OS versions.&lt;/p&gt;

&lt;p&gt;For a hit testing example, look at the code listed in &lt;a href=&quot;http://stackoverflow.com/q/1143704/116862&quot;&gt;this Stack Overflow question&lt;/a&gt;. Unlike the author claims in the question (which dates from 2009), the necessary &lt;a href=&quot;https://developer.apple.com/library/ios/documentation/graphicsimaging/reference/CGContext/Reference/reference.html#//apple_ref/doc/uid/TP30000950-CH1g-SW15&quot;&gt;&lt;code&gt;CGContextCopyPath()&lt;/code&gt;&lt;/a&gt; function is a public API since iOS 4.0/Mac OS X 10.6.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;Or the equivalent &lt;code&gt;containsPoint:&lt;/code&gt; method of &lt;code&gt;UIBezierPath&lt;/code&gt; or &lt;code&gt;NSBezierPath&lt;/code&gt;. Again, the distinction is not important because we can assume that these methods either just call the function on the internal &lt;code&gt;CGPath&lt;/code&gt; object they manage or work the same way.&lt;a href=&quot;#fnref:1&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;As always, this method has its own user interface issues. Users might assume that a shape’s interior is indeed the selectable region and fail to select a shape that only reacts to taps on its outline. Also, a narrow outline is much harder to hit so we have to ensure our tap targets are big enough.&lt;a href=&quot;#fnref:2&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot;&gt;
      &lt;p&gt;When the user moves the shape to another location, the &lt;code&gt;Shape&lt;/code&gt; class would create an appropriate transformation matrix for the translation and then apply the translation to the &lt;code&gt;UIBezierPath&lt;/code&gt; it manages by calling &lt;code&gt;[path applyTransform:…];&lt;/code&gt;. Even though these transforms are supposed to be applied on the path itself, accessing the path repeatedly from &lt;code&gt;drawRect:&lt;/code&gt; always returned the original, untransformed object, thereby drawing the selection outline in the wrong location. Only when I made an explicit copy of the path, it seemed to finally apply the cumulated transformations. What’s curious about this is that this issue does not affect the &lt;code&gt;[path stroke];&lt;/code&gt; line above, so it only seems to be a problem if you access the &lt;code&gt;UIBezierPath&lt;/code&gt;’s underlying &lt;code&gt;CGPath&lt;/code&gt;.&lt;a href=&quot;#fnref:3&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2012/02/schulung-ios-entwicklung-einsteiger-maerz-2012/</id>
    <title>Schulung iOS-Entwicklung für Einsteiger im März 2012</title>
    <published>2012-02-02T18:31:00Z</published>
    <updated>2012-02-13T08:39:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2012/02/schulung-ios-entwicklung-einsteiger-maerz-2012/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2012/02/schulung-ios-entwicklung-einsteiger-maerz-2012/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p class=&quot;update&quot;&gt;&lt;strong&gt;Update 13. Februar 2012:&lt;/strong&gt; Leider musste ich die Schulung im März absagen, eine Anmeldung ist daher nicht mehr möglich.&lt;/p&gt;

&lt;p lang=&quot;en&quot;&gt;&lt;em&gt;On March 5-7, 2012, I will be teaching another &lt;a href=&quot;/teaching/ios-schulung-maerz-2012/&quot;&gt;three-day workshop on iOS Development for Beginners&lt;/a&gt;. The course will be held in Berlin and the teaching language will be German. If you read this blog it is (a) likely that you already know quite a bit about iOS development and (b) relatively unlikely that you speak German, but if you know someone who does (b) but not (a) and would like to learn (a) and (c) is in Berlin, please point them &lt;a href=&quot;/teaching/ios-schulung-maerz-2012/&quot;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Es ist mal wieder soweit: wie schon im letzten Jahr veranstalte ich auch 2012 wieder eine &lt;a href=&quot;/teaching/ios-schulung-maerz-2012/&quot;&gt;Schulung zur iOS-Entwicklung für Einsteiger&lt;/a&gt; in Berlin, und zwar vom 5. bis 7. März 2012 (Montag bis Mittwoch). Nachdem der zweitägige Workshop letztes Jahr sich zeitlich als etwas knapp herausgestellt hat, habe ich die Schulung noch einmal neu konzipiert und nun auf drei Tage ausgelegt. Zielgruppe sind alle, die schon etwas Programmiererfahrung in anderen Umgebungen mitbringen, sich mit dem iOS SDK, Xcode und Objective-C aber noch nicht auseinandergesetzt haben. Wenn du schon immer einen Einstieg in die iOS-Programmierung gesucht, aber bisher nie die Zeit dafür gefunden hast, dich richtig damit zu beschäftigen, glaube ich, dass dieser Workshop genau das Richtige für dich ist. Ich würde mich freuen! &lt;a href=&quot;/teaching/ios-schulung-maerz-2012/&quot;&gt;Infos zu Preisen und Anmeldung findest du auf der Schulungsseite&lt;/a&gt;.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2012/01/docsets-app-for-ios/</id>
    <title>DocSets App for iOS</title>
    <published>2012-01-31T14:28:00Z</published>
    <updated>2012-05-10T15:20:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2012/01/docsets-app-for-ios/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2012/01/docsets-app-for-ios/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p class=&quot;update&quot;&gt;&lt;strong&gt;Update May 10, 2012:&lt;/strong&gt; In the meantime, Ole has submitted DocSets to the App Store and perhaps surprisingly, Apple approved it. I encourage you to &lt;a href=&quot;http://itunes.apple.com/us/app/docsets/id509945577?mt=8&quot;&gt;buy the app on the App Store&lt;/a&gt; both to support Ole and make future updates easier.&lt;/p&gt;

&lt;p&gt;Have you ever tried to use Apple’s developer documentation on your iOS device? While Apple does have a special iPad version of their online documentation at &lt;a href=&quot;http://developer.apple.com/library/ios/ipad/&quot;&gt;developer.apple.com/library/ios/ipad/&lt;/a&gt;, I find it quite frustrating to use. And that’s not so much because Apple did a bad job with it but because of the inherent problems of a web-based solution: the whole thing is just too slow.&lt;/p&gt;

&lt;p&gt;Now there is a better solution: my friend and officemate (and namesake) &lt;a href=&quot;http://omz-software.de/&quot;&gt;Ole Moritz&lt;/a&gt; wrote a native iOS app named &lt;a href=&quot;https://github.com/omz/DocSets-for-iOS&quot;&gt;DocSets&lt;/a&gt; for reading Apple’s developer documentation on the iPad or iPhone. DocSets is not available on the App Store. Instead, you can &lt;a href=&quot;https://github.com/omz/DocSets-for-iOS&quot;&gt;download the source code from GitHub&lt;/a&gt; for free and build it for yourself.&lt;/p&gt;

&lt;div class=&quot;with-caption&quot; style=&quot;width:660px;&quot;&gt;
  &lt;p&gt;&lt;a href=&quot;/media/docsets-ios-screenshot.png&quot; class=&quot;img-link&quot;&gt;&lt;img src=&quot;/media/docsets-ios-screenshot-660px.png&quot; alt=&quot;Screenshots of DocSets on iPhone and iPad&quot;&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;The DocSets app on iPhone and iPad. Screenshots: Ole Moritz.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;The app does not come with the actual documentation, but it includes links to all of Apple’s current doc sets (iOS SDK 5.0, 4.3, 4.2 and Mac OS X 10.7, 10.6) and lets you download the ones you’re interested in with a single tap. When the download is complete, you have full offline access to the documentation. Other documents in Apple’s docset format can be added manually via iTunes File Sharing or by adding the link to the docset directly to the &lt;code&gt;AvailableDocSets.plist&lt;/code&gt; file in the Xcode project.&lt;/p&gt;

&lt;div class=&quot;with-caption&quot; style=&quot;width:642px;&quot;&gt;
  &lt;p&gt;&lt;img src=&quot;/media/docsets-availabledocsets-plist-642px.png&quot; alt=&quot;`AvailableDocSets.plist`&quot;&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;Edit this property list to add more downloadable doc sets to the app.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;If you ever wanted to have offline access to Apple’s developer documentation on your iOS device, the DocSets app is a great tool.&lt;/p&gt;

&lt;p&gt;PS: Ole also wrote &lt;a href=&quot;https://github.com/omz/AppSales-Mobile&quot;&gt;AppSales&lt;/a&gt;, another open-source app that is worth checking out if you don’t have it. AppSales is an iOS app for downloading and analyzing your sales numbers from the iOS and Mac App Stores.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2012/01/new-videos-at-developer-apple-com/</id>
    <title>New Videos at developer.apple.com</title>
    <published>2012-01-27T18:10:00Z</published>
    <updated>2012-01-27T18:10:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2012/01/new-videos-at-developer-apple-com/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2012/01/new-videos-at-developer-apple-com/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;Most of you probably know of the &lt;a href=&quot;http://developer.apple.com/videos/wwdc/2011/&quot;&gt;WWDC session videos&lt;/a&gt; Apple posts to its developer site each year. These videos are invaluable resources for learning about new technologies and APIs directly from their creators. Since 2010, the WWDC videos are free for all registered Apple developers so you really have no excuse for not watching them.&lt;/p&gt;

&lt;h1&gt;New Videos with iOS 5 Tech Talk Content&lt;/h1&gt;

&lt;p&gt;Occasionally, Apple even updates its selection of developer videos outside the annual WWDC cycle. In fact, Apple just posted 10 new videos to &lt;a href=&quot;http://developer.apple.com/videos/ios/&quot;&gt;developer.apple.com/videos/ios/&lt;/a&gt; in December 2011:&lt;/p&gt;

&lt;div class=&quot;with-caption&quot; style=&quot;width:660px;&quot;&gt;
  &lt;p&gt;&lt;img src=&quot;/media/new-videos-developer-apple-com-screenshot-660px.png&quot; alt=&quot;List of Video Titles: Building and Optimizing Websites for iOS, Game Center Essentials, In-App Purchase and Notification Essentials, Ingredients of Great Apps, iPhone and iPad User Interface Design, Optimizing App Performance with Instruments, Providing Context, Tuning OpenGL ES Games, Understanding iOS View Compositing, Working with Video in iOS&quot;&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;The list of new videos posted to &lt;a href=&quot;http://developer.apple.com/videos/ios/&quot;&gt;developer.apple.com/videos/ios/&lt;/a&gt; in December 2011.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Some of these new videos deal with the same topics that Apple focused on in its recent &lt;a href=&quot;http://developer.apple.com/techtalk/&quot;&gt;iOS 5 Tech Talk world tour&lt;/a&gt;, so if you haven’t had the chance to attend one of the Tech Talks, watching the videos brings you much of the same content. For instance, the video titled &lt;em&gt;Optimizing App Performance with Instruments&lt;/em&gt;, presented by Michael Jurewitz, follows &lt;a href=&quot;http://oleb.net/blog/2011/11/ios5-tech-talk-michael-jurewitz-on-performance-measurement/&quot;&gt;Michael’s Tech Talk session on Performance Measurement&lt;/a&gt; pretty closely.&lt;/p&gt;

&lt;p&gt;Other videos I recommend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Ingredients of Great Apps&lt;/em&gt; with John Geleynse.&lt;/li&gt;
  &lt;li&gt;
&lt;em&gt;Understanding iOS View Compositing&lt;/em&gt; with Bill Dudney.&lt;/li&gt;
  &lt;li&gt;
&lt;em&gt;Tuning OpenGL ES Games (using Instruments)&lt;/em&gt; with Allan Schaffer.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;To download the new videos, go to &lt;a href=&quot;http://developer.apple.com/videos/ios/&quot;&gt;developer.apple.com/videos/ios/&lt;/a&gt;. It seems they are available for free for all registered iOS developers, just like the WWDC videos.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2012/01/gesture-recognition-on-ios-with-attention-to-detail/</id>
    <title>Gesture Recognition on iOS with Attention to Detail</title>
    <published>2012-01-25T17:08:00Z</published>
    <updated>2012-01-25T17:08:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2012/01/gesture-recognition-on-ios-with-attention-to-detail/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2012/01/gesture-recognition-on-ios-with-attention-to-detail/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;One of the things that sets the iPhone’s user interface apart from the competition is Apple’s incredible attention to detail. This attention does not only extend to every single pixel on the screen but, perhaps even more important, also to gesture recognition: the standard iOS controls do a lot of smart things in order to identify the gesture the user intended to make and to allow multiple gestures to be executed at the same time if appropriate.&lt;/p&gt;

&lt;p&gt;For example, scroll views must distinguish between a simple tap and the beginning of a swipe gesture. Similarly, the built-in map view control allows pinching and scrolling in one simultaneous gesture (put two fingers on the screen and you can switch seamlessly between pinching and scrolling without having to “restart” the gesture).&lt;/p&gt;

&lt;h1&gt;Half-assed Gesture Recognition Is Not Good Enough&lt;/h1&gt;

&lt;p&gt;We should set ourselves the same high standards for our own apps. In this article, I would like to show you an example where the half-assed implementation of gesture recognition seems to work well enough at first glance. But as the user continues to use the app, they quickly stumble upon little irritations, small annoyances in the user interface that they perhaps cannot even pinpoint but notice nevertheless. And while these irritations do not seem to be a big deal to many developers, I want to show you how getting rid of them can improve the user experience tremendously.&lt;/p&gt;

&lt;div class=&quot;with-caption&quot; style=&quot;width:660px;&quot;&gt;
  &lt;p&gt;&lt;a href=&quot;/media/gesture-recognition-sample-app-screenshot.png&quot; class=&quot;img-link&quot;&gt;&lt;img src=&quot;/media/gesture-recognition-sample-app-screenshot-660px.png&quot; alt=&quot;The sample gesture recognition app.&quot;&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;The sample app: using the standard gestures, you can drag the image across the screen, make it bigger or smaller by pinching, and rotate it. A double tap resets the image to its original state.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;For our example, imagine a simple app that lets the user play around with an image on screen. Using gestures, they can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag the image across the screen.&lt;/li&gt;
  &lt;li&gt;Make it bigger or smaller.&lt;/li&gt;
  &lt;li&gt;Rotate it.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;In addition, a double tap should reset the image to its original position and size.&lt;/p&gt;

&lt;p&gt;To implement this app we need to create four &lt;a href=&quot;http://developer.apple.com/library/IOs/#documentation/UIKit/Reference/UIGestureRecognizer_Class/Reference/Reference.html&quot;&gt;gesture recognizers&lt;/a&gt;, one for each required gesture. The setup code for the app would look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;viewDidLoad
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;super&lt;/span&gt; viewDidLoad&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView.userInteractionEnabled &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; YES&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    
    UIPanGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;panRecognizer &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;UIPanGestureRecognizer alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithTarget&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; action&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwc&quot;&gt;@selector&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;panDetected&lt;span class=&quot;hl opt&quot;&gt;:)];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView addGestureRecognizer&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;panRecognizer&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    UIPinchGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;pinchRecognizer &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;UIPinchGestureRecognizer alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithTarget&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; action&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwc&quot;&gt;@selector&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;pinchDetected&lt;span class=&quot;hl opt&quot;&gt;:)];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView addGestureRecognizer&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;pinchRecognizer&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    UIRotationGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;rotationRecognizer &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;UIRotationGestureRecognizer alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithTarget&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; action&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwc&quot;&gt;@selector&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;rotationDetected&lt;span class=&quot;hl opt&quot;&gt;:)];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView addGestureRecognizer&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;rotationRecognizer&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    UITapGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;tapRecognizer &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;UITapGestureRecognizer alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithTarget&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; action&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwc&quot;&gt;@selector&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;tapDetected&lt;span class=&quot;hl opt&quot;&gt;:)];&lt;/span&gt;
    tapRecognizer.numberOfTapsRequired &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl num&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView addGestureRecognizer&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;tapRecognizer&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is pretty straightforward code. Enable user interaction on our image view (which is disabled by default) and then create the gesture recognizers one by one and add them to the image view. The implementation of the gesture recognizer actions is equally simple:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;panDetected&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UIPanGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;panRecognizer
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    CGPoint translation &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;panRecognizer translationInView&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.view&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    CGPoint imageViewPosition &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView.center&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    imageViewPosition.x &lt;span class=&quot;hl opt&quot;&gt;+=&lt;/span&gt; translation.x&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    imageViewPosition.y &lt;span class=&quot;hl opt&quot;&gt;+=&lt;/span&gt; translation.y&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView.center &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; imageViewPosition&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;panRecognizer setTranslation&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;CGPointZero inView&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.view&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;pinchDetected&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UIPinchGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;pinchRecognizer
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    CGFloat scale &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; pinchRecognizer.scale&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView.transform &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;CGAffineTransformScale&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView.transform&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; scale&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; scale&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
    pinchRecognizer.scale &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl num&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;rotationDetected&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UIRotationGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;rotationRecognizer
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    CGFloat angle &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; rotationRecognizer.rotation&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView.transform &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;CGAffineTransformRotate&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView.transform&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; angle&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
    rotationRecognizer.rotation &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl num&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;tapDetected&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UITapGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;tapRecognizer
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;UIView animateWithDuration&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;0.25&lt;/span&gt; animations&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;^&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView.center &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;CGPointMake&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwd&quot;&gt;CGRectGetMidX&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.view.bounds&lt;span class=&quot;hl opt&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;hl kwd&quot;&gt;CGRectGetMidY&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.view.bounds&lt;span class=&quot;hl opt&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.imageView.transform &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; CGAffineTransformIdentity&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ole/GestureRecognition/zipball/plain-gestures&quot;&gt;Download the code for the sample app at this stage&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;Works But Does Not Feel Great&lt;/h1&gt;

&lt;p&gt;Build and run this app, preferably on a device (testing the effectiveness of gestures on the simulator is not the best idea). If you are like me, using the app feels okay but not great. In fact, there are several problems with the gestures:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
    &lt;p&gt;The gestures only work when all fingers are placed on the image view. This can get quite difficult when the target view is small, especially when two fingers are required as for pinching and rotating. It is possible for the user to make the image so small that it is almost impossible to recover from the situation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;None of the gestures work simultaneously with others. If I want to rotate the image but accidentally begin a pinch gesture, I have to release my fingers and start over. I cannot pinch, rotate and drag the image in one fluid motion.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;There is no momentum at play here. All movements stop immediately when the user lifts their fingers off the screen.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;We will solve points 1 and 2 in this post. I will cover the third issue in another article.&lt;/p&gt;

&lt;h1&gt;Solving the UX Issues&lt;/h1&gt;

&lt;p&gt;The first problem is trivial to solve: rather than adding the gesture recognizers to the image view, we add them directly to its superview (the view controller’s view). That way, the user can use the entire screen for gestures. It does not matter whether two, one or no fingers hit the image view. Modify &lt;code&gt;viewDidLoad&lt;/code&gt; to implement this change:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;viewDidLoad
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;super&lt;/span&gt; viewDidLoad&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    UIPanGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;panRecognizer &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;UIPanGestureRecognizer alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithTarget&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; action&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwc&quot;&gt;@selector&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;panDetected&lt;span class=&quot;hl opt&quot;&gt;:)];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.view addGestureRecognizer&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;panRecognizer&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    UIPinchGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;pinchRecognizer &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;UIPinchGestureRecognizer alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithTarget&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; action&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwc&quot;&gt;@selector&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;pinchDetected&lt;span class=&quot;hl opt&quot;&gt;:)];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.view addGestureRecognizer&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;pinchRecognizer&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    UIRotationGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;rotationRecognizer &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;UIRotationGestureRecognizer alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithTarget&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; action&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwc&quot;&gt;@selector&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;rotationDetected&lt;span class=&quot;hl opt&quot;&gt;:)];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.view addGestureRecognizer&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;rotationRecognizer&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    UITapGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;tapRecognizer &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;UITapGestureRecognizer alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithTarget&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; action&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwc&quot;&gt;@selector&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;tapDetected&lt;span class=&quot;hl opt&quot;&gt;:)];&lt;/span&gt;
    tapRecognizer.numberOfTapsRequired &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl num&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.view addGestureRecognizer&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;tapRecognizer&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For the second issue, we need to tell the gesture recognizers to work simultaneously. The default behavior of gesture recognizers is to block each other: only one gesture can be recognized at a time. Fortunately, that behavior is easy to modify. Every gesture recognizer will ask its delegate (if it has one) whether it should be allowed to recognize gestures simultaneously with any other gesture recognizer it comes in conflict with. By setting our view controller as the delegate of all our gesture recognizers and simply returning &lt;code&gt;YES&lt;/code&gt; from the &lt;a href=&quot;http://developer.apple.com/library/IOs/documentation/UIKit/Reference/UIGestureRecognizerDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UIGestureRecognizerDelegate/gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:&quot;&gt;&lt;code&gt;gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:&lt;/code&gt;&lt;/a&gt; delegate method, we can tell them to work together.&lt;/p&gt;

&lt;p&gt;Don’t forget to add the &lt;a href=&quot;http://developer.apple.com/library/IOs/#documentation/UIKit/Reference/UIGestureRecognizerDelegate_Protocol/Reference/Reference.html&quot;&gt;&lt;code&gt;UIGestureRecognizerDelegate&lt;/code&gt;&lt;/a&gt; protocol to our view controller’s interface declaration and extend the &lt;code&gt;viewDidLoad&lt;/code&gt; method as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;viewDidLoad
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
	...
	
    panRecognizer.delegate &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    pinchRecognizer.delegate &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    rotationRecognizer.delegate &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl slc&quot;&gt;// We don't need a delegate for the tapRecognizer&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And implement the delegate method:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;gestureRecognizer&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UIGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UIGestureRecognizer &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;otherGestureRecognizer
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; YES&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ole/GestureRecognition/zipball/improved-gestures&quot;&gt;Download the code for the sample app at this stage&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now try out the app again. With a few simple changes, the gestures feel much more fluid and natural. It is attention to detail like this that distinguishes the really good iOS apps from the mediocre one. As mentioned, stay tuned for a future post on how to handle momentum when working with gesture recognizers. &lt;a href=&quot;https://github.com/ole/GestureRecognition&quot;&gt;The code for the sample app is hosted on GitHub&lt;/a&gt;.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2012/01/initWithNibName-bundle-breaks-encapsulation/</id>
    <title>initWithNibName:bundle: Breaks Encapsulation</title>
    <published>2012-01-23T18:00:00Z</published>
    <updated>2012-01-27T18:43:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2012/01/initWithNibName-bundle-breaks-encapsulation/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2012/01/initWithNibName-bundle-breaks-encapsulation/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p class=&quot;update&quot;&gt;&lt;strong&gt;Update January 27, 2012:&lt;/strong&gt; Aaron Hillegass himself &lt;a href=&quot;http://weblog.bignerdranch.com/?p=129&quot;&gt;blogged about this same topic&lt;/a&gt; already in August 2009. Be sure to also read his post. Thanks to &lt;a href=&quot;http://0xced.blogspot.com/&quot;&gt;Cédric Luthi&lt;/a&gt; for pointing this out to me.&lt;/p&gt;

&lt;p&gt;Here is an interesting approach that I recently learned from reading &lt;a href=&quot;http://www.bignerdranch.com/instructors/conway_joe&quot;&gt;Joe Conway’s&lt;/a&gt; and &lt;a href=&quot;http://www.bignerdranch.com/instructors/hillegass.shtml&quot;&gt;Aaron Hillegass’s&lt;/a&gt; excellent introductory book &lt;a href=&quot;http://www.amazon.com/iOS-Programming-Ranch-Guide-Guides/dp/0321773772/&quot;&gt;iOS Programming: The Big Nerd Ranch Guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have done any iOS programming, you have probably encountered a pattern like this countless times:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;IBAction&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;openNextView&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;sender
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    MyCustomViewController &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;nextViewController &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;MyCustomViewController alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; 
        initWithNibName&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;MyCustomViewController&quot;&lt;/span&gt; bundle&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; presentViewController&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;nextViewController animated&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;YES completion&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl slc&quot;&gt;// or:&lt;/span&gt;
    &lt;span class=&quot;hl slc&quot;&gt;// [self.navigationController pushViewController:nextViewController animated:YES];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In response to an event (the user tapping a button), we create and initialize a new view controller instance, using the designated initializer of the &lt;code&gt;UIViewController&lt;/code&gt; class, &lt;code&gt;initWithNibName:bundle:&lt;/code&gt;. The we present the view controller on the screen. This pattern is ubiquitous in Apple’s documentation and sample code. But is it good code?&lt;/p&gt;

&lt;h1&gt;The Name of the NIB File is an Implementation Detail&lt;/h1&gt;

&lt;p&gt;Does it make sense for a view controller initializer to have an argument for the name of the view’s NIB file? In other words, should the creator of the view controller decide what NIB file it should load its view from? No. As Joe and Aaron mention in the book&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, the name of its NIB file is an implementation detail that should only concern the view controller itself. Exposing this detail to an outside caller breaks the &lt;a href=&quot;http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)&quot;&gt;encapsulation principle&lt;/a&gt; object-oriented programming is based on.&lt;/p&gt;

&lt;p&gt;Since we usually subclass &lt;code&gt;UIViewController&lt;/code&gt; to create our own custom view controllers, fixing this design flaw is easy. We just override the standard &lt;code&gt;init&lt;/code&gt; method and document it to be our new designated initializer. In that method, we hardcode the values for &lt;code&gt;nibName&lt;/code&gt; and &lt;code&gt;bundle&lt;/code&gt; and call the superclass’s designated initializer with them:&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl kwc&quot;&gt;@implementation&lt;/span&gt; MyCustomViewController
    
&lt;span class=&quot;hl slc&quot;&gt;// This is the designated initializer&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;init
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    NSString &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;nibName &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; @&lt;span class=&quot;hl str&quot;&gt;&quot;MyCustomViewController&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    NSBundle &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;bundle &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;super&lt;/span&gt; initWithNibName&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;nibName bundle&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;bundle&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
        ...
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We must also override the old designated initializer to reroute it to use the new one:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;initWithNibName&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;NSString &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;nibName bundle&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;NSBundle &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;bundle
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;hl slc&quot;&gt;// Disregard parameters - nib name is an implementation detail&lt;/span&gt;
	&lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, whenever we need to create a new view controller, we just call &lt;code&gt;init&lt;/code&gt; rather than &lt;code&gt;initWithNibName:bundle:&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;One View Controller, Multiple NIBs&lt;/h1&gt;

&lt;p&gt;In some cases it can actually make sense to initialize the same view controller with different NIB files. The prime example is different UIs for iPhone and iPad that are contained in separate NIB files but served by the same view controller.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; But in this case, too, it should be the view controller itself that decides what NIB file to load. The logic for the decision should be placed into its &lt;code&gt;init&lt;/code&gt; method:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;init
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    NSString &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;nibName &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwd&quot;&gt;UI_USER_INTERFACE_IDIOM&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;() ==&lt;/span&gt; UIUserInterfaceIdiomPhone&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
        nibName &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; @&lt;span class=&quot;hl str&quot;&gt;&quot;MyCustomViewControllerPhone&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
        nibName &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; @&lt;span class=&quot;hl str&quot;&gt;&quot;MyCustomViewControllerPad&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    NSBundle &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;bundle &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;super&lt;/span&gt; initWithNibName&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;nibName bundle&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;bundle&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
        ...
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return self&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And even if the logic which NIB file to load depends on an external value that is only known to the creator of the view controller, it is better design to define a custom &lt;code&gt;init...&lt;/code&gt; method that takes the external value as a parameter than to expose the name of the NIB file directly. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl slc&quot;&gt;// This is the designated initializer&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;initWithContext&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;MyViewControllerContext&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;context
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl slc&quot;&gt;// Decide which NIB file to load depending on the value of context&lt;/span&gt;
    ...
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Even though the flaw in Apple’s design of the &lt;code&gt;UIViewController&lt;/code&gt; initializers is pretty obvious, it never occurred to me before I read about it in the Big Nerd Ranch book. So thanks again to Joe and Aaron for pointing it out. In the future, I will define my own designated initializer for all my custom view controllers and not expose the view controller’s NIB file to outside callers anymore.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;On page 174 of the second edition.&lt;a href=&quot;#fnref:1&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;&lt;span class=&quot;update&quot;&gt;&lt;strong&gt;Update January 27, 2012:&lt;/strong&gt; Several people pointed out to me that, as long as I give my NIB file the same name as my view controller class (I can even omit the &lt;code&gt;Controller&lt;/code&gt; part), it is strictly not necessary to specify the &lt;code&gt;nibName&lt;/code&gt; explicitly here. Just call &lt;code&gt;[super initWithNibName:nil bundle:nil];&lt;/code&gt;. This is true, but I feel the explicit specification of the NIB file adds a lot of clarity. Also note that implicitly passing &lt;code&gt;nil&lt;/code&gt; does not fix the inherent design flaw. You still have to override &lt;code&gt;initWithNibName:bundle:&lt;/code&gt; to make sure that no outside caller can specify a different NIB name.&lt;/span&gt;&lt;a href=&quot;#fnref:2&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot;&gt;
      &lt;p&gt;&lt;span class=&quot;update&quot;&gt;&lt;strong&gt;Update January 27, 2012:&lt;/strong&gt; Many readers noted that this contrived example is not the best and I agree. If you name your NIB files following an Apple-specified pattern (iPhone-specific files end in &lt;code&gt;~iphone.xib&lt;/code&gt;, iPad-specific ones in &lt;code&gt;~ipad.xib&lt;/code&gt;), you can just specifiy the base filename in code and the NIB loading system will automatically figure out the correct file (this also works for other resources such as images, by the way). This is the better way to distinguish between different resources for the different platforms. Take the sample code above as a general example on how you would let the view controller decide on the correct NIB file name in different cases.&lt;/span&gt;&lt;a href=&quot;#fnref:3&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2012/01/ios-and-mac-development-link-roundup-december-2011/</id>
    <title>iOS and Mac Development Link Roundup: December 2011</title>
    <published>2012-01-01T13:23:00Z</published>
    <updated>2012-01-01T15:45:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2012/01/ios-and-mac-development-link-roundup-december-2011/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2012/01/ios-and-mac-development-link-roundup-december-2011/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;Here is my summary of the past month in links.&lt;/p&gt;

&lt;h1&gt;Carrier IQ&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;The&lt;/em&gt; story at the beginning of the month was the Carrier IQ software that &lt;a href=&quot;http://www.wired.com/threatlevel/2011/11/secret-software-logging-video/&quot;&gt;Trevor Eckhart found on his Android phone&lt;/a&gt;, logging a lot of seemingly privacy-related activity. Grant Paul quickly found out that &lt;a href=&quot;http://blog.chpwn.com/post/13572216737&quot;&gt;Carrier IQ also is on iOS&lt;/a&gt;, although Apple was quick to affirm that it has never used the software for anything that’s not covered by their privacy policy and only collected usage data if users explicitly opted in.&lt;/p&gt;

&lt;p&gt;As the days went by, what seemed like a huge scandal at first turned out to have been blown out of proportion. Still, some phone carriers are to be blamed for using Carrier IQ’s software to track things like &lt;a href=&quot;http://vulnfactory.org/blog/2011/12/05/carrieriq-the-real-story/&quot;&gt;the applications used or what URLs are visited by a user&lt;/a&gt; (information which, admittely, they know anyway).&lt;/p&gt;

&lt;h1&gt;Programming&lt;/h1&gt;

&lt;h2&gt;Android Graphics Architecture vs. iOS&lt;/h2&gt;

&lt;p&gt;There has been an interesting discussion about the shortcomings (or not) of Android’s graphics architecture vs. iOS. It’s hard to follow the original discussion now because many of the posts have been edited but let’s recap: &lt;/p&gt;

&lt;p&gt;Dianne Hackborn, Android engineer at Google, set out to correct some assumptions about Android’s internals in a post titles &lt;a href=&quot;https://plus.google.com/105051985738280261832/posts/2FXDCz8x93s&quot;&gt;How about some Android graphics true facts?&lt;/a&gt;. Andrew Munn, former intern on the Android team, followed up with his (misinformed) post &lt;a href=&quot;https://plus.google.com/100838276097451809262/posts/VDkV9XaJRGS&quot;&gt;The Reason Android is Laggy&lt;/a&gt;, claiming the main advantage of iOS’s over Android’s architecture was that iOS used &lt;q&gt; a dedicated UI thread with real-time priority&lt;/q&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://plus.google.com/105051985738280261832/posts/XAZ4CeVP6DC&quot;&gt;another follow-up post&lt;/a&gt;, Dianne Hackborn rejected this claim, instead naming the security model and the design of certain APIs as reasons for Android’s past performance problems. Several people also pointed out flaws in Andrew’s description of how iOS actually works (see &lt;a href=&quot;https://plus.google.com/100838276097451809262/posts/VDkV9XaJRGS&quot;&gt;Andrew Munn’s updated post&lt;/a&gt;). Bob Lee’s post &lt;a href=&quot;http://blog.crazybob.org/2011/12/truth-about-android-ios-ui-performance.html&quot;&gt;The truth about Android &amp;amp; iOS UI performance&lt;/a&gt; on the topic is worth reading, too.&lt;/p&gt;

&lt;p&gt;In conclusion, it’s probably fair to say that with Android 4.0, the technical differences between iOS and Android in terms of graphics rendering are pretty small. I really like Brent Royal-Gordon’s take on the topic, quoted by Andrew Munn:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;All that stuff you noticed—the way images aren’t drawn into lists while you’re scrolling, the way WebKit rendering stops when the system is tracking a touch—isn’t inherently built-in by a mechanism that pauses the world when a finger is on the screen.* It’s deliberate behavior painstakingly implemented by the developer of each individual app.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;This is not a technical difference; it’s a cultural difference. Good iOS developers don’t ship software until it runs at something near 60 fps while scrolling and tracks touches almost perfectly; good Android developers do. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.mikeash.com/pyblog/friday-qa-2011-12-30-disassembling-the-assembly-part-3-arm-edition.html&quot;&gt;Disassembling the Assembly, Part 3: ARM edition&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Gwynne Raskind gives a good introduction to reading ARM assembly language. This can be useful for intense iOS debugging sessions or if you just want to better understand your compiler. Don’t miss &lt;a href=&quot;http://www.mikeash.com/pyblog/friday-qa-2011-12-16-disassembling-the-assembly-part-1.html&quot;&gt;part 1&lt;/a&gt; and &lt;a href=&quot;http://www.mikeash.com/pyblog/friday-qa-2011-12-23-disassembling-the-assembly-part-2.html&quot;&gt;part 2&lt;/a&gt; of the series covering x86_64 assembly.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;https://github.com/levey/QuadCurveMenu&quot;&gt;QuadCurveMenu&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Zhu Levey created an open-source implementation of the animated fly-out menu made popular this month by the redesigned Path app. While I hope we won’t see this kind of menu in every second app in the future, the code can help illustrate some advanced Core Animation techniques.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://blog.madefm.com/post/13817640556/ios-devcorner-attaching-an-info-panel-to-a&quot;&gt;Attaching an info panel to a UIScrollViewIndicator like in the Path 2 app&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Another UI gem in the new Path app is the floating clock that scrolls and animates with the main scroll view to indicate the position of the timeline. Florian Mielke shows how to mimic this behavior in your own view controller.&lt;/p&gt;

&lt;p class=&quot;update&quot;&gt;&lt;strong&gt;Update Janurary 1, 2012:&lt;/strong&gt; &lt;a href=&quot;https://github.com/andrewroycarter/TimeScroller&quot;&gt;TimeScroller&lt;/a&gt; by Andrew Roy Carter is another take on this. Andrew’s solution goes a little further and actually reproduces the look of the control in the Path app including the clock.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://kickingbear.com/blog/archives/264&quot;&gt;A Dynamic Siri&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Guy English on the possibility of Apple providing developer access to Siri in the future.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I predict that a Siri API is further off than you might think. The integration of services into Siri appears to be on a very case by case basis and even an internal app required special consideration. … Apple doesn’t appear to have an internal API for Siri yet, and it’s my bet that they’re a year or so away from it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;&lt;a href=&quot;http://subjectiveobserver.wordpress.com/2011/12/04/economies-of-scalar/&quot;&gt;Economies of Scalar&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Someone naming herself Subjective Observer points out a very useful new Core Data option in iOS 5 and OS X Lion. The Core Data editor now lets you “use scalar properties for primitive data types” instead of &lt;code&gt;NSNumber&lt;/code&gt;, generating accessors based on scalar data types for numeric attributes. That is a great and largely undocumented addition! She also shows how to make use of this new feature while maintaining compatibility with older OS versions.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://joshua.nozzi.name/2011/11/nib-segregation/&quot;&gt;Nib Segregation&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;It’s common Cocoa wisdom and the rule to put each window into its own NIB file. Joshua Nozzi argues that it’s not always beneficial, though. &lt;q&gt;Blind adherence to generalizations will get you in trouble.&lt;/q&gt;&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://vendorkit.com/&quot;&gt;VendorKit&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;VendorForge and Vendor, two of the Cocoa package managers I mentioned in &lt;a href=&quot;/blog/2011/11/ios-and-mac-development-link-roundup-november-2011/&quot;&gt;last month’s link roundup&lt;/a&gt;, have merged to form VendorKit. I hope to see more of this. One package manager to rule them all! (Provided it’s a good one.)&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://aussiebloke.blogspot.com/2011/12/constant-confusion.html&quot;&gt;Constant Confusion&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Stuart Carnie clears up a syntax rule in C that always eluded me before: where to put the &lt;code&gt;const&lt;/code&gt; keyword in a complex declaration? The answer is, of course, it depends on whether you want a constant pointer to a mutable value or a mutable pointer to a constant value or a constant pointer to a constant value. For all these cases, Stuart comes up with an easy-to-remember rule:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Always write &lt;code&gt;const&lt;/code&gt; to the right and read the declaration from right to left.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Simple as that.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.bonto.ch/blog/2011/12/08/json-libraries-for-ios-comparison-updated/&quot;&gt;JSON Libraries for iOS Comparison&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;“Junior B.” compared the performance of various open-source JSON libraries to Apple’s new built-in JSON parser in Cocoa. Result: on iOS, JSONKit is up to ~30% faster than Apple’s &lt;code&gt;NSJSONSerialization&lt;/code&gt;. SBJSON and TouchJSON are much slower than both.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;https://github.com/chrismiles/CMPopTipView&quot;&gt;CMPopTipView&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;CMPopTipView by Chris Miles is a view component that can display a UIPopover-like “bubble”, containing a text message, pointing at a specified button or view. Looks good for help texts.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://bjango.com/articles/pngcompression/&quot;&gt;PNG compression and iOS apps&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Mark Edwards analyzes the benefits of trying to optimize PNG images for your apps.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’m going to come straight out and say it—if you’re spending any effort compressing or optimising your PNG images for iOS app development, you’re wasting your time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;&lt;a href=&quot;http://toxicsoftware.com/uistoryboard-issues/&quot;&gt;UIStoryboard Issues&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Great post by Jonathan Wight on the current shortcomings of Storyboarding in iOS 5 apps. Jonathan’s verdict is that, while Storyboarding is a promising concept, it isn’t yet mature enough to be used in a complex app. I was particularly struck by the section titled “Misuse sender field”. It really seems Apple has forgotten to provide an essential API here.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.friday.com/bbum/2011/12/18/retaincount-is-useless/&quot;&gt;retainCount is useless&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;If you ever find yourself logging retain counts while trying to debug a memory management problem, remember Bill Bumgarner’s post and stop what you’re doing immediately.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://gamesfromwithin.com/trying-out-multisampling-on-ios&quot;&gt;Trying Out Multisampling On iOS&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Noel Llopis investigates the benefits and performance drawbacks of using OpenGL multisampling in iOS. In his testing with the Flower Garden app, the performance impact varied greatly by device: almost none on the iPhone 3GS and iPad 2, huge impact on the iPad 1 and iPhone 4 (whose GPU is less capable relative to the amount of pixels they have to handle).&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;https://github.com/AlanQuatermain/AQSocket&quot;&gt;AQSocket&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Jim Dovey wrote a simple socket class that illustrates how to work with Grand Central Dispatch’s dispatch sources and dispatch I/O channels. Both are GCD features that are usually not addressed in your typical GCD tutorial so Jim’s code should be very useful if you want to learn more about the topic.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;https://github.com/ChiefPilot/F3BarGauge&quot;&gt;F3BarGauge&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;F3BarGauge by Brad Benson is a customizable iOS control to display bar gauges. Useful for your next audio mixer/visualizer app.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.zucchiniframework.org/&quot;&gt;Zucchini&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Zucchini is a new visual iOS testing framework, inspired by the &lt;a href=&quot;http://cukes.info/&quot;&gt;Cucumber framework&lt;/a&gt;, which is very popular in the Ruby community. You write your tests in CoffeeScript, which Zucchini then compiles down to Apple’s UIAutomation Javascript syntax. Jake Marsh already &lt;a href=&quot;http://deallocatedobjects.com/posts/zucchini-visual-ios-testing-written-in-coffeescript&quot;&gt;blogged about Zucchini&lt;/a&gt;. Looks promising.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://spin.atomicobject.com/2011/12/13/building-a-universal-framework-for-ios/&quot;&gt;Building a Universal Framework for iOS&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Justin DeWind wrote an up-to-date tutorial on building frameworks in Xcode that include multiple architectures such as armv6, armv7, and i386. This is especially useful for developers of open-source components. Or you can build your own frameworks if you want to easily mix ARC and non-ARC code without the hassle of specifying per-file compiler flags.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://altdevblogaday.com/2011/12/24/static-code-analysis/&quot;&gt;Static Code Analysis&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;John Carmack talks about the huge benefits he got from using static code analysis in his projects. The discussion of particular tools is C/C++-centric and thus not directly applicable to Objective-C code but his general findings are interesting:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The most important thing I have done as a programmer in recent years is to aggressively pursue static code analysis.  Even more valuable than the hundreds of serious bugs I have prevented with it is the change in mindset about the way I view software reliability and code quality. … I feel the success that we have had with code analysis has been clear enough that I will say plainly it is irresponsible to not use it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lesson for Cocoa developers: at least use the Clang Static Analyzer that’s built into Xcode regularly.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://blog.chpwn.com/post/14612320117&quot;&gt;Siri Authentication&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Grant Paul reverse-engineered how Siri authentication works, thereby ensuring that it only runs on an iPhone 4S (or for hacks you need an iPhone 4S device token). This is his overview.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://gamesfromwithin.com/icloud-demystified&quot;&gt;iCloud Demystified&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Noel Llopis gives a good tutorial (including a demo project) how to sync files with iCloud in the simplest way possible (without using &lt;code&gt;UIDocument&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://blog.bluelightninglabs.com/2011/12/suppressing-xcode-warnings-on-a-per-file-basis/&quot;&gt;Suppressing Xcode Warnings On A Per File Basis&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Nice little tip by Shane Crawford. Especially useful if you use some open source library whose author did not care to fix all compiler warnings.&lt;/p&gt;

&lt;h1&gt;Design&lt;/h1&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.jessicahische.is/obsessedwiththeinternet/andbeingresponsivelyinspired/inspiration-vs-imitation-2&quot;&gt;Inspiration vs. Imitation&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Great post by Jessica Hische on the fine line between being inspired by others and using this inspiration to create something original and blatantly copying others’ creations. &lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://blackpixel.com/blog/1458/what-goes-into-the-sausage-the-creation-of-an-icon/&quot;&gt;What Goes into the Sausage – The Creation of an Icon&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Michael Shephard from Black Pixel about the iterative and non-linear nature of the design process. Nice insight.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://carpeaqua.com/2011/12/04/on-magazines-and-the-ipad/&quot;&gt;On Magazines and the iPad&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Justin Williams shows what happens when media companies create apps for the sake of having an app rather than to create a better user experience. &lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’m convinced that the people who actually write for magazines, edit them and publish them have never actually tried using their iPad versions for more than a few moments. If they actually did try to use their publication’s app as the actual means to read each issue, things would have to improve. Right? RIGHT?!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.uiparade.com/&quot;&gt;UI Parade&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;UI Parade is another one of the sites that collect examples of outstanding UI design. I mentioned a number of these over the past months in my blog posts but this one seems particularly well edited.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://discovr.info/2011/12/ux-design-experiments-for-a-number-1-mobile-app/&quot;&gt;UX design experiments for a Number 1 mobile app&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;David McKinney illustrates different approaches how to integrate help into your app’s UI. I like the integrated approach they settled on very much.&lt;/p&gt;

&lt;h2&gt;The Flipboard for iPhone design process&lt;/h2&gt;

&lt;p&gt;After Flipboard for the iPhone came out earlier this month, members of the design team tweeted some pictures showing the many, many iterations they did for this one app’s design. I love how the photos illustrate the incredible amount of work that went into it.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://instagr.am/p/X3b4p/&quot; class=&quot;img-link&quot;&gt;&lt;img src=&quot;http://distilleryimage1.s3.amazonaws.com/e7432e64212511e19896123138142014_7.jpg&quot; alt=&quot;Flipboard for iPhone Design Prototype 1&quot; width=&quot;200&quot; height=&quot;200&quot;&gt;&lt;/a&gt; &lt;a href=&quot;http://twitter.com/marumushi/status/144900441153617922&quot; class=&quot;img-link&quot;&gt;&lt;img src=&quot;http://distilleryimage8.s3.amazonaws.com/7724c43c21d711e180c9123138016265_7.jpg&quot; alt=&quot;Flipboard for iPhone Design Prototype 2&quot; width=&quot;200&quot; height=&quot;200&quot;&gt;&lt;/a&gt; &lt;a href=&quot;http://twitter.com/craigmod/status/144863019166466048&quot; class=&quot;img-link&quot;&gt;&lt;img src=&quot;https://instagr.am/p/YADhv/media/?size=l&quot; alt=&quot;Flipboard for iPhone Design Prototype 3&quot; width=&quot;200&quot; height=&quot;200&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://startingup.me/post/13738882378/path-2&quot;&gt;UX Critique of Path 2&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Brenden Mulligan took a very detailed look at the new Path app from a design and user experience point of view. Very insightful and spot-on.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://carpeaqua.com/2011/12/22/texture/&quot;&gt;Texture&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Justin Williams on the importance of texture in the iOS UI. Justin gives examples of some new apps that to him feel out of place on iOS because their design is based on solid colors without texture, which seems more fitting in Android and Windows Phone environments. He points out the importance of designing especially for the target platform:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Mobile is young enough that we’ve got three vibrant platforms that offer uniquely identifiable experiences jockeying for position. If your goal is to reach all of those customers, do it with respect and taste. Build something tailored specifically for them, not something that is just “good enough” for all three.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;&lt;a href=&quot;http://vimeo.com/33991213&quot;&gt;Beth on Brushes&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Fraser Speirs posted a video that shows how competently his 4-year-old daughter uses the Brushes app on the iPad to paint a picture. Again and again, it’s amazing to see how much more intuitive these post-PC devices are compared to a classical mouse-driven GUI.&lt;/p&gt;

&lt;h1&gt;App Store&lt;/h1&gt;

&lt;h2&gt;&lt;a href=&quot;https://plus.google.com/115711522874757126523/posts/BBn6UjDiDLU&quot;&gt;How to to climb in the App Store, Part II&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Oliver Reichenstein continued to analyze and publish iA’s pricing experiments with their app, iA Writer. The takeaway from this for developers seems to be: trying out different price points is fine and all but in the end, the quality and uniqueness of your app will be a much bigger sales driver:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;To increase sales: Don’t imitate. You might get some crumbs from some table but ultimately, you’ll help the original by doing so. Innovate. Think different, be different. Take maximum care for details, even if it’s a hassle. Read all feedback and don’t get irritated by feature requests and focus on the next big step.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.splatf.com/2011/12/path-rank/&quot;&gt;And now a reminder of how tough the App Store slog really is&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Taking the new Path app as an example, Dan Frommer points out how hard it is to be successful on the App Store these days, even if you made a great product and got as much press as those guys did. A few days later, Dan followed up with &lt;a href=&quot;http://www.splatf.com/2011/12/path-top-25/&quot;&gt;a post showing that in Path’s case&lt;/a&gt; at least, the app finally made it into the top 25. So it may be hard, but it’s definitely not impossible.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.apple.com/pr/library/2011/12/12Apples-Mac-App-Store-Downloads-Top-100-Million.html&quot;&gt;Apple’s Mac App Store Downloads Top 100 Million&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;In a press release, Apple announced some numbers for the Mac App Store now that it is almost one year old. 100 million app downloads in less than a year sure sound impressive until you compare it to the size of the iOS App Store, which registers about 1 &lt;em&gt;billion&lt;/em&gt; downloads &lt;em&gt;a month&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In other words, the iOS App Store is about 50-100 times bigger than the Mac App Store in terms of downloads. Interestingly, the relation is about the same when you count the total number of available apps (500,000 for iOS vs. less than 10,000 on the Mac App Store). So arguably, because it’s so much easier to get your share of visibility on the Mac App Store, your chances of making money could be roughly equal on both stores, especially since Mac apps tend to be priced higher.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.splatf.com/2011/12/macappstore-100million/&quot;&gt;A look at the Mac App Store, 100 million downloads later&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Dan Frommer also takes a look at the numbers in the Mac App Store. According to his statistics, only &lt;q&gt;about 18 apps are added to the Mac App Store each day&lt;/q&gt;. Surprising.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://blog.flurry.com/bid/79061/App-Developers-Bet-on-iOS-over-Android-this-Holiday-Season&quot;&gt;App Developers Bet on iOS over Android this Holiday Season&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;According to Flurry (who have unique data on many mobile app stats thanks to their analytics software), app developers still favor iOS over Android by a wide margin despite Android’s tremendous growth in market share. The main reason seems to be that the App Store is where the money is.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.distimo.com/blog/2011_12_distimo-releases-full-year-2011-publication/&quot;&gt;Distimo Releases Full Year 2011 Publication&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Research firm Distimo published an updated report on the mobile app store field in 2011. Key findings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The iOS App Store generates about four times the revenue that the Android Market makes.&lt;/li&gt;
  &lt;li&gt;In-app purchases and freemium business models have an increasing share of the total revenue.&lt;/li&gt;
  &lt;li&gt;The app market in China is growing fast.&lt;/li&gt;
&lt;/ol&gt;&lt;h2&gt;&lt;a href=&quot;http://www.insidemobileapps.com/2011/12/14/free-to-play-pioneer-nimblebit-say-to-put-fun-and-user-experience-first-not-monetization/&quot;&gt;Free-to-Play Pioneer NimbleBit Says to Put Fun and User Experience First, Not Monetization&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Good interview by Kathleen De Vere with David and Ian Marsh, the twin brothers behind Tiny Tower. They talk about monetization strategies on the App Store and the increasing role of “freemium” business models. Surprisingly to me, 30% of the revenue they make with Tiny Tower comes from selling $30 in-app purchases, even though these items only make up 4% of all their in-app purchases. Goes to show that it pays off to give your most loyal users the chance to give you more than $0.99.&lt;/p&gt;

&lt;h1&gt;Community&lt;/h1&gt;

&lt;h2&gt;&lt;a href=&quot;http://mattgemmell.com/2011/12/05/latest-version/&quot;&gt;Latest Version&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Matt Gemmell makes the tongue-in-cheek argument that it is okay to only support the latest OS version. And I actually agree (up to a point).&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.kernelmag.com/scene/2011/12/developers-developers-developers/&quot;&gt;The Golden Age of the Developer&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;David Haywood Smith from The Kernel says there has never been a better time to be a developer. There are countless resources and opportunities available to us. The only thiing we have to do is consume them. But at the same time, David reminds us that we all have the responsibility to give something back to this awesome community. Everybody should think about how they can contribute. And to all those who already do contribute, do not sit back:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The big challenge is leading. It’s not as scary as it sounds. It’s really just an extension of contributing. If you make a significant contribution then you automatically become a leader. … I encourage you to start thinking about how to move up the ladder. Whatever kind of developer you are, you’ll find it pays dividends.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;&lt;a href=&quot;http://mattgemmell.com/2011/12/19/open-source-code/&quot;&gt;Open Source Code&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;On the same topic, Matt Gemmell has some very useful tips on how to publish some of your code in open-source form. By following Matt’s advice, you increase the chances that your open-source project will actually be noticed significantly. Even if your code is absolutely amazing, almost no one will look at it if you don’t package it nicely and make it easy for others to use.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://net.tutsplus.com/articles/general/from-idea-to-market-how-we-built-gradient/&quot;&gt;From Idea to Market: How We Built Gradient&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Nicola Armellini from Jumpzero talks about the development process of their Mac app, Gradient. I love how he stresses to start out with a simple idea that solves a real problem and the importance of prototyping and showing what you do to possible influencers far before it’s done.&lt;/p&gt;

&lt;h1&gt;Competition&lt;/h1&gt;

&lt;h2&gt;&lt;a href=&quot;http://googleblog.blogspot.com/2011/12/10-billion-android-market-downloads-and.html&quot;&gt;10 Billion Android Market downloads and counting&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Google reported on their blog that the Android Market has reached 10 billion app downloads. The current growth rate of the Market is 1 billion downloads per month, similar to the current growth of the iOS App Store.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://shiftyjelly.wordpress.com/2011/12/08/standing-up-for-android/&quot;&gt;Standing Up For Android&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;The guys from Shifty Jelly make quite a convincing point for iOS developers to also look at the opportunities of the Android community.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In many ways it’s [the Android Market] a better place to be than iOS, since so many developers are ignoring it, and yet there is a massive install base waiting to give you their money.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’m sure there are many Android developers who would agree. So why all the controversy? Let everyone decide on their own which platform they want to target (first). I am sure some will follow &lt;a href=&quot;http://julianyap.com/2011/12/08/What-Eric-Schmidt-actually-said.html&quot;&gt;Eric Schmidt’s prediction&lt;/a&gt; and others (probably most, at least in the next 6 months) will not.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.zdnet.com/blog/microsoft/microsoft-to-drop-desktop-app-from-windows-8-arm-tablets/11325&quot;&gt;Microsoft to drop Desktop App from Windows 8 ARM tablets?&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Mary Jo Foley writes that Microsoft may make a 180 degree turn and actually make Windows 8 tablets Metro only, not bringing over the traditional Windows desktop. I think that would be a great move for Microsoft.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://blogs.msdn.com/b/windowsstore/archive/2011/12/06/announcing-the-new-windows-store.aspx&quot;&gt;Previewing the Windows Store&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Antoine Leblond from Microsoft gives developers a preview of the upcoming app store for Windows 8. Their feature set sounds great:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We have full platform support for free apps, trials (both time-based and feature-based trials) and paid apps, including in-app purchase. And we have sales analytics that will help you target customers more effectively.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In addition, developers will get an 80% revenue share (instead of the usual 70%) if their app is successful enough to make it over $25,000 in total revenue. Let’s hope that more competition in the app store space will give Apple the incentive to further improve their offerings.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.hp.com/hpinfo/newsroom/press/2011/111209xa.html&quot;&gt;HP to Contribute webOS to Open Source&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Press release by HP. Will it make a difference? Will other major players like Facebook or Amazon now adopt webOS for their own devices? In an interview with Joshua Topolsky for The Verge, HP CEO Meg Whitman and board member Marc Andreessen at least confirmed that HP has plans to make new tablets running webOS, &lt;q&gt;but what I can’t tell you is whether that will be in 2012 or not&lt;/q&gt;.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.alasdairmonk.com/journal/twenty-four-hours-of-lumia/&quot;&gt;Twenty four hours of Lumia&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Alasdair Monk’s is one of a number of very positive reviews of the Lumia 800, Nokia first device running Windows Phone 7.5. The phone is stunning and the software looks great too. Looking at the market reaction, it still seems to have come too late.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.guardian.co.uk/technology/blog/2011/dec/30/nokia-lumia-800-goodbye&quot;&gt;Goodbye, Nokia Lumia 800: £400 and one month on, it didn’t work out&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Matthew Baxter-Reynolds just published a rather negative review of his Lumia 800 experience over the last month, citing many minor flaws both in the built-in software and in third-party apps.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What’s wrong is the niggles. Windows Phone is a good operating system. But it’s not a great operating system. … It’s the niggles that’s stopped me from developing a deeper relationship with the device that turns it into a ubiquitous tool, as opposed to “just a phone”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;Apple and Steve Jobs&lt;/h1&gt;

&lt;h2&gt;&lt;a href=&quot;http://techcrunch.com/2011/12/30/apple-2011/&quot;&gt;Apple’s Terrific And Tumultuous 2011&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;MG Siegler summarizes Apple’s 2011 for Techcrunch in a long list of links. Very useful post for reference if you want to find a particular article again.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.splatf.com/2011/12/apple-2011-lessons/&quot;&gt;10 things we learned about Apple this year&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Dan Frommer highlights some key points how Apple works and acts. Realizing these traits will probably make it much easier to tell if the next random Apple rumor has any value or not. Most important lesson for developers: &lt;q&gt;The iPad really is special.&lt;/q&gt; If you did not know that already.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://techcrunch.com/2011/12/09/apple-made-a-deal-with-the-devil-no-worse-a-patent-troll/&quot;&gt;Apple Made A Deal With The Devil (No, Worse: A Patent Troll)&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Apple has been extremely busy recently suing its competitors (and being sued by them) for patent infringement, copycat design, etc. I think it’s fair to say that it has become impossible to say who’s right and who’s wrong overall. Not so in this particular case: Jason Kincaid seems to have uncovered that Apple may have cooperated with a patent troll. To quote Jason, it’s &lt;q&gt;hard to see Apple in a positive light here&lt;/q&gt;.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://blog.thomasqbrady.com/post/13639200852/steve-jobs-by-walter-isaacson-a-review&quot;&gt;Steve Jobs by Walter Isaacson: A Review&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Thomas Q. Brady with a well-written and well-founded critique of the Jobs biography. Brady makes many of the same points I already &lt;a href=&quot;http://5by5.tv/hypercritical/42&quot;&gt;heard from John Siracusa&lt;/a&gt;, so this is a good article to read if you don’t listen to podcasts.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.iphoneincanada.ca/iphone-news/apple-submits-updated-campus-2-plans-to-cupertino-reveals-stunning-renderings/&quot;&gt;Apple Submits Updated Campus 2 Plans to Cupertino, Reveals Stunning Renderings&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Gary Ng’s article includes links to many new renderings and plans of Apple’s stunning plans for the new corporate campus.&lt;/p&gt;

&lt;h2&gt;&lt;a href=&quot;http://www.forbes.com/sites/onmarketing/2011/12/14/the-real-story-behind-apples-think-different-campaign/&quot;&gt;The Real Story Behind Apple’s “Think Different” Campaign&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;In the Steve Jobs biography, Walter Isaacson suggests that Steve Jobs himself wrote much of the “Here’s to the Crazy Ones” text for Apple’s famous &lt;em&gt;Think Different&lt;/em&gt; campaign. In this interesting article for Forbes, Rob Siltanen, member of the original advertising team, tells a different story. Obviously, this is not development-related at all, but it is a good read.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2011/12/uirequireddevicecapabilities-cannot-be-changed-in-app-updates/</id>
    <title>UIRequiredDeviceCapabilities Cannot Be Changed in App Updates</title>
    <published>2011-12-23T15:53:00Z</published>
    <updated>2012-05-10T15:15:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2011/12/uirequireddevicecapabilities-cannot-be-changed-in-app-updates/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2011/12/uirequireddevicecapabilities-cannot-be-changed-in-app-updates/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;div class=&quot;update&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Update May 10, 2012:&lt;/strong&gt; Apple replied to my bug report:&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;Engineering has determined that this issue behaves as intended based on the following information: Developers can add restrictions to &lt;code&gt;UIRequiredDeviceCapabilities&lt;/code&gt; on app updates provided any device that is dropped cannot support the min os version specified.&lt;/p&gt;
  &lt;/blockquote&gt;
&lt;/div&gt;

&lt;div class=&quot;update&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Update January 11, 2012:&lt;/strong&gt; Added a screenshot of the Xcode validation error.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Earlier this month, I wrote about &lt;a href=&quot;/blog/2011/12/how-to-restrict-your-ios-app-to-modern-hardware/&quot;&gt;How to Restrict Your iOS App to Modern Hardware&lt;/a&gt;. One of the suggestions I made was to use the &lt;code&gt;UIRequiredDeviceCapabilities&lt;/code&gt; key in your &lt;code&gt;Info.plist&lt;/code&gt; file to make your app run only on devices with armv7 CPUs. Several people contacted me afterwards to tell me that this approach only works for new apps.&lt;/p&gt;

&lt;p&gt;You heard that right: &lt;strong&gt;when updating an app, it seems you cannot add new restrictions to the Required Device Capabilities.&lt;/strong&gt; One developer who contacted me said he has &lt;q&gt;been fighting with this for more than 2 years&lt;/q&gt;, and all due to the simple mistake of omitting the “telephony” requirement in version 1.0 of his app.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h2&gt;Automatic Rejection by Xcode’s Validator&lt;/h2&gt;

&lt;p&gt;According to the feedback I got, this is not even an issue that could be discussed during the app review process. Instead, it seems that the automatic validation service that Apple has integrated into Xcode will reject any update with more restrictive &lt;code&gt;UIRequiredDeviceCapabilities&lt;/code&gt; than the earlier version before you can even upload it to iTunes Connect.&lt;/p&gt;

&lt;div class=&quot;with-caption&quot; style=&quot;width:600px&quot;&gt;
  &lt;p&gt;&lt;img src=&quot;/media/xcode-validation-uirequireddevicecapabilities.jpg&quot; alt=&quot;Xcode validation error after updating UIRequiredDeviceCapabilities.&quot;&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;Xcode validation error after updating UIRequiredDeviceCapabilities. &lt;a href=&quot;http://twitter.com/noel_llopis/status/156428438994042880&quot;&gt;Screenshot by Noel Llopis&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;h1&gt;How About Not Changing the Deployment Target for Your App’s Lifetime?&lt;/h1&gt;

&lt;p&gt;I think this is a very bad rule on Apple’s side and I wonder how it can be reconciled with other Apple policies regarding app updates. Ultimately, raising the required device capabilities is equivalent to increasing your app’s Deployment Target&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, something that Apple has no problem with in an app update.&lt;/p&gt;

&lt;p&gt;One could argue that from the perspective of the users, &lt;a href=&quot;http://twitter.com/olemoritz/status/142587108509491200&quot;&gt;a minimum OS version is easier to communicate than changed hardware requirements&lt;/a&gt; but I find that unconvincing. If anything, changed hardware requirements should be easier to understand than changes on the software side since every user knows that hardware cannot be updated while it’s a lot harder to grasp why an old device should not be able to run a new OS version. And Apple does a bad job of communicating changed OS version requirements anyway so it strikes me as odd that they should care so much about the hardware side of things.&lt;/p&gt;

&lt;p&gt;In addition, there are some hardware features Apple actively pushes, encouraging developers to adopt them in their apps. The prime example is probably the non-backwards compatible OpenGL ES 2.0. During the recent iOS 5 Tech Talks, &lt;a href=&quot;/blog/2011/11/ios5-tech-talk-allan-schaffer-opengl-es-glkit/&quot;&gt;Apple actively rallied developers to switch to OpenGL ES 2&lt;/a&gt; to make their apps better. But how is a developer supposed to switch from OpenGL ES 1.1 to 2.0 if he is not permitted to add the corresponding &lt;code&gt;UIRequiredDeviceCapabilities&lt;/code&gt; key to its updated app? In that case, he would be forced to increase the Deployment Target to iOS 4.3+ (all devices that run iOS 4.3 also support OpenGL ES 2.0) and his &lt;code&gt;Info.plist&lt;/code&gt; would not reflect the correct hardware requirements anymore. Looks like a bad workaround to me.&lt;/p&gt;

&lt;h2&gt;Downgrades are Possible&lt;/h2&gt;

&lt;p&gt;It is worth noting that the other way – lowering the required device capabilities – is indeed possible. One developer told me that they had no problems when they &lt;em&gt;removed&lt;/em&gt; a requirement from their app.&lt;/p&gt;

&lt;h1&gt;Please File a Bug Report&lt;/h1&gt;

&lt;p&gt;If you also think this is a bad policy that Apple should change, please &lt;a href=&quot;https://bugreport.apple.com/&quot;&gt;file a bug report&lt;/a&gt;. Feel free to refer to the bug ID under which I reported the problem: rdar://10623835.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;To quote from this developer’s e-mail to me: &lt;q&gt;I exchanged several emails with Apple support but they reject to change this even in this exceptional and logical case&lt;/q&gt;.&lt;a href=&quot;#fnref:1&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;In Apple’s terminology, the Deployment Target indicates the minimum OS version that an app can run on. For instance, setting the Deployment Target of an app to iOS 4.3 has the same effect in practice as using the &lt;code&gt;UIRequiredDeviceCapabilities&lt;/code&gt; to restrict the app to the armv7 architecture because the sets of all iOS devices that can run iOS 4.3 and have an armv7-capable CPU are identical. Apple takes measures to avoid the installation of apps on devices that do not fulfill the Deployment Target requirements.&lt;a href=&quot;#fnref:2&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2011/12/diamond-dash-for-ios/</id>
    <title>Diamond Dash for iOS</title>
    <published>2011-12-08T20:45:00Z</published>
    <updated>2011-12-08T20:45:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2011/12/diamond-dash-for-ios/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2011/12/diamond-dash-for-ios/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;&lt;em&gt;Disclaimer: my brother Jens is Wooga’s founder and CEO. It is unlikely that I would have been involved in this project if that were not the case, if only for the fact that I would probably never have learned about it in the first place. That said, I think we managed to separate family and business quite well.&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;align-left&quot; style=&quot;width:128px;&quot;&gt;
  &lt;p&gt;&lt;img src=&quot;/media/diamond-dash-ios-app-icon.png&quot; alt=&quot;Diamond Dash for iOS App Icon&quot;&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Yesterday at the Le Web conference in Paris, social game developer &lt;a href=&quot;http://www.wooga.com/2011/12/diamond-dash-mobile/&quot;&gt;Wooga launched Diamond Dash for iPhone and iPad&lt;/a&gt;, their first native iOS title. Diamond Dash originally launched as a Flash game on Facebook in March 2011 and, with more than 11 million active players per month, today is one of the top 10 games on the platform.&lt;/p&gt;

&lt;p&gt;During the past months, I helped port the game to iOS. Our goal was to make the iOS version even more fun to play than the game on Facebook, and I think we succeeded. The simple gameplay makes Diamond Dash a perfect game for touchscreen control and the incredibly fast-paced action comes across perfectly on both iPhone and iPad. Although the gameplay is trivial (tap groups of 3 or more same-colored gems to make them explode), it is highly addictive and I encourage you to try it out.&lt;/p&gt;

&lt;div class=&quot;with-caption&quot; style=&quot;width:700px;&quot;&gt;
  &lt;p&gt;&lt;img src=&quot;/media/wooga-diamond-dash-ios-screenshot.png&quot; alt=&quot;Diamond Dash on iPad and iPhone.&quot;&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;Diamond Dash on iPad and iPhone. Photo: Wooga.&lt;/p&gt;
&lt;/div&gt;

&lt;h1&gt;Facebook Integration&lt;/h1&gt;

&lt;p&gt;Because of Diamond Dash’s Facebook heritage, it was clear from the beginning that the iOS version should also have a deep Facebook integration. While it is possible to play standalone, it really is a lot more fun to play against your Facebook friends and compete in the Weekly Tournament. Your scores are synced between all three platforms (Facebook, iPhone and iPad) so no matter where you or your friends play, you can always compete with each other. Not every iPhone user may like this deep Facebook integration, but I think for a game that already has such a huge fan base on Facebook, it makes total sense.&lt;/p&gt;

&lt;p&gt;From a developer’s perspective, the tight integration with Facebook and the existing game backend turned out to be one of the challenges of the project. In the end, we were able to take advantage of some brand-new Facebook features that were rolled out in Facebook’s latest version of their native iOS app. Viral channels that were limited to the Facebook website until a few weeks ago can now be used by developers to link directly to their native iOS or Android app &lt;a href=&quot;https://developers.facebook.com/docs/guides/mobile/&quot;&gt;through the Facebook app on the device&lt;/a&gt;. My brother (and Wooga CEO) Jens talked about this &lt;a href=&quot;http://www.ustream.tv/recorded/18988725&quot;&gt;when he introduced Diamond Dash at Le Web&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;Already Featured by Apple&lt;/h1&gt;

&lt;div class=&quot;with-caption align-right&quot; style=&quot;width:520px;&quot;&gt;
  &lt;p&gt;&lt;img src=&quot;/media/diamond-dash-ios-ratings.png&quot; alt=&quot;Initial ratings for Diamond Dash on the App Store in Germany: 727 ratings with a 4.5 star average.&quot;&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;Ratings for Diamond Dash on the German App Store less than 48 hours after it went live.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;I am incredibly excited about the huge initial success that Diamond Dash seems to be. Just 24 hours after its announcement, the game has already been featured by Apple and made it to the top 10 free apps all over Europe (3rd in Turkey, 4th in Germany, 6th in France, 7th in Italy, 9th in Spain). It’s currently ranked 79th and climbing among all free apps in the US.&lt;/p&gt;

&lt;p&gt;User feedback also seems to be very positive. On the German App Store, Diamond Dash already got more than 700 ratings and reviews with an average of 4.5 stars. Thanks to all players for the positive reception! If you want to be one of them, &lt;a href=&quot;http://itunes.apple.com/us/app/diamond-dash/id461402734?ls=1&amp;amp;mt=8&quot;&gt;get Diamond Dash for free in the App Store&lt;/a&gt;.&lt;/p&gt;

&lt;iframe width=&quot;640&quot; height=&quot;360&quot; src=&quot;http://www.youtube.com/embed/V3eTDwy5CUY?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;
&lt;/iframe&gt;

&lt;h1&gt;Thanks to the Arcade Team at Wooga&lt;/h1&gt;

&lt;p&gt;I would also like to say thanks to the incredible team I could work with at &lt;a href=&quot;http://www.wooga.com/&quot;&gt;Wooga&lt;/a&gt;. I think we can be quite proud of the job we did. I wish them the best for the continued development of the game (in which I will no longer be involved).&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2011/12/tutorial-how-to-sort-and-group-uitableview-by-date/</id>
    <title>Tutorial: How to Sort and Group UITableView by Date</title>
    <published>2011-12-02T17:40:00Z</published>
    <updated>2011-12-21T16:00:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2011/12/tutorial-how-to-sort-and-group-uitableview-by-date/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2011/12/tutorial-how-to-sort-and-group-uitableview-by-date/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;div class=&quot;with-caption align-right&quot; style=&quot;width:300px&quot;&gt;
  &lt;p&gt;&lt;img src=&quot;/media/appointmentlist-screenshot-iphone.png&quot; alt=&quot;Screenshot of the Appointment List sample application. The list of calendar events ids grouped by date.&quot;&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;The Appointment List sample application. The list of calendar events ids grouped by date.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Let me follow up on last month’s little series about &lt;a href=&quot;http://oleb.net/blog/2011/11/working-with-date-and-time-in-cocoa-part-1/&quot;&gt;date and time handling in Cocoa&lt;/a&gt; with a practical example.&lt;/p&gt;

&lt;p&gt;Say you want to implement a list of your future appointments similar to the List view in Apple’s Calendar app on the iPhone. Calendar events should be listed in a table view, with each day getting its own section. So we have to group the dates by day, which is an interesting task to get familiar with the date handling classes.&lt;/p&gt;

&lt;h1&gt;Project Setup&lt;/h1&gt;

&lt;p&gt;I am not going to cover the basics here. We need a fresh Xcode project (the navigation-based app template is a good start) with a view controller that displays a &lt;code&gt;UITableView&lt;/code&gt;. Since we are going to work with the calendar store on the device, we also need to link our app with the EventKit.framework and import the framework’s header file: &lt;code&gt;#import &amp;lt;EventKit/EventKit.h&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;Getting Events from the Calendar Store&lt;/h1&gt;

&lt;p&gt;The first thing we have to do is get a list of future events from the calendar store. Our interface to the store is the &lt;a href=&quot;http://developer.apple.com/library/ios/#documentation/EventKit/Reference/EKEventStoreClassRef/Reference/Reference.html&quot;&gt;&lt;code&gt;EKEventStore&lt;/code&gt;&lt;/a&gt; class. The event store lets us generate a predicate that we can then use to retrieve all events matching the predicate. All we need to do is specify a start and end date for the predicate.&lt;/p&gt;

&lt;h2&gt;Constructing Start and End Date&lt;/h2&gt;

&lt;p&gt;Say we want to list all events between today and one year from today. A natural start date for our query would be &lt;code&gt;[NSDate date]&lt;/code&gt;, which gives us the current date and time. But what about appointments that were scheduled for earlier today? I think we should include them in our list even though they lie in the past. It’s better than to confuse the user by showing only part of today’s events.&lt;/p&gt;

&lt;p&gt;So our start date should be the beginning of the current day. How do we determine that date, given that all we have is the current date and time? Think about it this way: we want a date that represents a specific time (00:00) on a given day. The easiest way to do that is to selectively convert the date components of the given date into an &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDateComponents_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003642&quot;&gt;&lt;code&gt;NSDateComponents&lt;/code&gt;&lt;/a&gt; instance, then set the specific time components manually, and convert the whole thing back into an &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003641&quot;&gt;&lt;code&gt;NSDate&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;NSDate &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;dateAtBeginningOfDayForDate&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;NSDate &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;inputDate
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl slc&quot;&gt;// Use the user's current calendar and time zone&lt;/span&gt;
    NSCalendar &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;calendar &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSCalendar currentCalendar&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    NSTimeZone &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;timeZone &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSTimeZone systemTimeZone&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;calendar setTimeZone&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;timeZone&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    &lt;span class=&quot;hl slc&quot;&gt;// Selectively convert the date components (year, month, day) of the input date&lt;/span&gt;
    NSDateComponents &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateComps &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;calendar components&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;inputDate&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    &lt;span class=&quot;hl slc&quot;&gt;// Set the time components manually&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateComps setHour&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateComps setMinute&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateComps setSecond&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;hl slc&quot;&gt;// Convert back       &lt;/span&gt;
    NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;beginningOfDay &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;calendar dateFromComponents&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;dateComps&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; beginningOfDay&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This method gives us an &lt;code&gt;NSDate&lt;/code&gt; representing midnight in the current user’s local time for the specified input date.&lt;/p&gt;

&lt;p&gt;For the end date, we want to add exactly one year to the start date. The trivial way to do that would be to add &lt;code&gt;365 * 24 * 60 * 60&lt;/code&gt; seconds&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; to the start date but this naive approach takes neither leap year nor different calendars into account. The better way is again the one via &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSCalendar_Class/Reference/NSCalendar.html#//apple_ref/doc/uid/TP40003626&quot;&gt;&lt;code&gt;NSCalendar&lt;/code&gt;&lt;/a&gt; and &lt;code&gt;NSDateComponents&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;NSDate &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;dateByAddingYears&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;NSInteger&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;numberOfYears toDate&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;NSDate &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;inputDate
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl slc&quot;&gt;// Use the user's current calendar&lt;/span&gt;
    NSCalendar &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;calendar &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSCalendar currentCalendar&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    NSDateComponents &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateComps &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSDateComponents alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateComps setYear&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;numberOfYears&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;newDate &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;calendar dateByAddingComponents&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;dateComps toDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;inputDate options&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; newDate&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;dateByAddingComponents:toDate:options:&lt;/code&gt; method is just great. It adds the specified date components to the input date and takes care of everything for us, including leap years and overflows from one unit to the next. For instance, if you were to add 5 months to a date in November, the method is smart enough to return a result in April of next year.&lt;/p&gt;

&lt;h2&gt;Querying the Calendar Store&lt;/h2&gt;

&lt;p&gt;Having start and end date, we can construct our search predicate. Add the following code to your view controller’s &lt;code&gt;viewDidLoad&lt;/code&gt; method:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;viewDidLoad
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;super&lt;/span&gt; viewDidLoad&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    
    NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;now &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSDate date&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;startDate &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; dateAtBeginningOfDayForDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;now&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;endDate &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; dateByAddingYears&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;1&lt;/span&gt; toDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;startDate&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;

    EKEventStore &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;eventStore &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;EKEventStore alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    NSPredicate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;searchPredicate &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;eventStore predicateForEventsWithStartDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;startDate endDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;endDate calendars&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    NSArray &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;events &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;eventStore eventsMatchingPredicate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;searchPredicate&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gives us a list of events inside our desired timeframe.&lt;/p&gt;

&lt;h1&gt;Grouping Events by Day&lt;/h1&gt;

&lt;p&gt;Next, we have to group the list of events into sections, each section representing a single day. The way we approach this task is this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Iterate over all events.&lt;/li&gt;
  &lt;li&gt;Reduce the event’s start date to its date components, i.e. strip off the time (like we did above to determine the start date of our search predicate).&lt;/li&gt;
  &lt;li&gt;Use the reduced date as key in a &lt;code&gt;sections&lt;/code&gt; dictionary.&lt;/li&gt;
  &lt;li&gt;Each value in the &lt;code&gt;sections&lt;/code&gt; dictionary should be an array containing the events that belong to the day represented by the corresponding key.&lt;/li&gt;
  &lt;li&gt;Create a separate array in which we sort the keys of the &lt;code&gt;sections&lt;/code&gt; dictionary. We need this to display the sections in the correct order.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Make sense? Here is the code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl kwc&quot;&gt;@property&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;strong&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; nonatomic&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt; NSMutableDictionary &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;sections&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl kwc&quot;&gt;@property&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;strong&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; nonatomic&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt; NSArray &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;sortedDays&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;

...

&lt;span class=&quot;hl kwc&quot;&gt;@synthesize&lt;/span&gt; sections&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl kwc&quot;&gt;@synthesize&lt;/span&gt; sortedDays&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;

...

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;viewDidLoad
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    ...

    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sections &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSMutableDictionary dictionary&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;EKEvent &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;event &lt;span class=&quot;hl kwa&quot;&gt;in&lt;/span&gt; events&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;hl slc&quot;&gt;// Reduce event start date to date components (year, month, day)&lt;/span&gt;
        NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateRepresentingThisDay &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt; dateAtBeginningOfDayForDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;event.startDate&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
        
        &lt;span class=&quot;hl slc&quot;&gt;// If we don't yet have an array to hold the events for this day, create one&lt;/span&gt;
        NSMutableArray &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;eventsOnThisDay &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sections objectForKey&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;dateRepresentingThisDay&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;eventsOnThisDay &lt;span class=&quot;hl opt&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
            eventsOnThisDay &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSMutableArray array&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
            
            &lt;span class=&quot;hl slc&quot;&gt;// Use the reduced date as dictionary key to later retrieve the event list this day&lt;/span&gt;
            &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sections setObject&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;eventsOnThisDay forKey&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;dateRepresentingThisDay&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
        
        &lt;span class=&quot;hl slc&quot;&gt;// Add the event to the list for this day&lt;/span&gt;
        &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;eventsOnThisDay addObject&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;event&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;hl slc&quot;&gt;// Create a sorted list of days&lt;/span&gt;
    NSArray &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;unsortedDays &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sections allKeys&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sortedDays &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;unsortedDays sortedArrayUsingSelector&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwc&quot;&gt;@selector&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;compare&lt;span class=&quot;hl opt&quot;&gt;:)];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(The method is getting pretty long here. In practice, I wouldn’t place all this code in  &lt;code&gt;viewDidLoad&lt;/code&gt; but it should suffice for the example.)&lt;/p&gt;

&lt;h1&gt;Creating Date Formatters for Output&lt;/h1&gt;

&lt;p&gt;That’s it! The last thing we need are two &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003643&quot;&gt;&lt;code&gt;NSDateFormatter&lt;/code&gt;&lt;/a&gt; objects to format the output for the section headers and cells in the table view. We could create those directly in the methods where we need them, but since creating a date formatter is a relatively expensive operation, we are better off creating them once and reusing them. Note that we don’t use specific date and time formats but instead rely on the predefined date formatter styles, which take the user’s preferences into account:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl kwc&quot;&gt;@property&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;strong&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; nonatomic&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt; NSDateFormatter &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;sectionDateFormatter&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl kwc&quot;&gt;@property&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;strong&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; nonatomic&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt; NSDateFormatter &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;cellDateFormatter&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;

...

&lt;span class=&quot;hl kwc&quot;&gt;@synthesize&lt;/span&gt; sectionDateFormatter&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl kwc&quot;&gt;@synthesize&lt;/span&gt; cellDateFormatter&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;

...

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;&lt;span class=&quot;hl kwb&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;viewDidLoad
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    ...

    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sectionDateFormatter &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSDateFormatter alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sectionDateFormatter setDateStyle&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSDateFormatterLongStyle&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sectionDateFormatter setTimeStyle&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSDateFormatterNoStyle&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.cellDateFormatter &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSDateFormatter alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.cellDateFormatter setDateStyle&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSDateFormatterNoStyle&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.cellDateFormatter setTimeStyle&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSDateFormatterShortStyle&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;Populating the Table View&lt;/h1&gt;

&lt;p&gt;With the groundwork done, populating the table view is simple. Note that I am using iOS 5 for the sample project so we can configure our prototype table cell directly in Interface Builder:&lt;/p&gt;

&lt;div class=&quot;with-caption&quot; style=&quot;width:645px&quot;&gt;
  &lt;p&gt;&lt;img src=&quot;/media/appointmentlist-interface-builder-prototype-cell-settings.png&quot; alt=&quot;Configuring the settings of the prototype cell in Interface Builder.&quot;&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;Configuring the settings of the prototype cell in Interface Builder.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;UITableViewDataSource&lt;/code&gt; protocol methods we have to implement are straightforward:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;NSInteger&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;numberOfSectionsInTableView&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UITableView &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;tableView
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sections count&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;NSInteger&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;tableView&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UITableView &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;tableView numberOfRowsInSection&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;NSInteger&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;section
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateRepresentingThisDay &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sortedDays objectAtIndex&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;section&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    NSArray &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;eventsOnThisDay &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sections objectForKey&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;dateRepresentingThisDay&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;eventsOnThisDay count&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;NSString &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;tableView&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UITableView &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;tableView titleForHeaderInSection&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;NSInteger&lt;span class=&quot;hl opt&quot;&gt;)&lt;/span&gt;section
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateRepresentingThisDay &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sortedDays objectAtIndex&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;section&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sectionDateFormatter stringFromDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;dateRepresentingThisDay&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;hl opt&quot;&gt;- (&lt;/span&gt;UITableViewCell &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;tableView&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;UITableView &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;tableView cellForRowAtIndexPath&lt;span class=&quot;hl opt&quot;&gt;:(&lt;/span&gt;NSIndexPath &lt;span class=&quot;hl opt&quot;&gt;*)&lt;/span&gt;indexPath
&lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
    NSString &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;reuseIdentifier &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; @&lt;span class=&quot;hl str&quot;&gt;&quot;EventTitleCell&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    UITableViewCell &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;cell &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;tableView dequeueReusableCellWithIdentifier&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;reuseIdentifier&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;

    NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateRepresentingThisDay &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sortedDays objectAtIndex&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;indexPath.section&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    NSArray &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;eventsOnThisDay &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.sections objectForKey&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;dateRepresentingThisDay&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    EKEvent &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;event &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;eventsOnThisDay objectAtIndex&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;indexPath.row&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;

    cell.textLabel.text &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; event.title&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;event.allDay&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
      cell.detailTextLabel.text &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; @&lt;span class=&quot;hl str&quot;&gt;&quot;all day&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;{&lt;/span&gt;
      cell.detailTextLabel.text &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;&lt;span class=&quot;hl kwa&quot;&gt;self&lt;/span&gt;.cellDateFormatter stringFromDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;event.startDate&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;hl kwa&quot;&gt;return&lt;/span&gt; cell&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h1&gt;Download the Sample Project&lt;/h1&gt;

&lt;p&gt;In this tutorial about date handling, I illustrated how to combine Cocoa’s date handling classes, &lt;code&gt;NSDate&lt;/code&gt;, &lt;code&gt;NSCalendar&lt;/code&gt;, &lt;code&gt;NSDateComponents&lt;/code&gt;, &lt;code&gt;NSDateFormatter&lt;/code&gt;, to do date calculations, to derive new dates from existing ones, to group dates according to your own criteria, and to format dates for output on screen. And incidentally, we also learned to query the device’s calendar store.&lt;/p&gt;

&lt;p&gt;I uploaded the &lt;a href=&quot;https://github.com/ole/AppointmentList&quot;&gt;small sample app to GitHub&lt;/a&gt;, please download it from there. &lt;span class=&quot;update&quot;&gt;&lt;strong&gt;Update December 21, 2011:&lt;/strong&gt; I mistakenly had not included the &lt;code&gt;.xcodeproj&lt;/code&gt; file in the repository. This mistake is now fixed, sorry for the confusion.&lt;/span&gt; Note that you won’t see anything but an empty table view when you run the app in the iOS Simulator since the simulator does not have a calendar store.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;The number of seconds in a normal (non-leap) year. The result is 31,536,000 seconds.&lt;a href=&quot;#fnref:1&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2011/12/how-to-restrict-your-ios-app-to-modern-hardware/</id>
    <title>How to Restrict Your iOS App to Modern Hardware</title>
    <published>2011-12-01T15:30:00Z</published>
    <updated>2011-12-23T15:58:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2011/12/how-to-restrict-your-ios-app-to-modern-hardware/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2011/12/how-to-restrict-your-ios-app-to-modern-hardware/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;Marco Arment posted &lt;a href=&quot;http://www.marco.org/2011/11/30/more-ios-device-and-os-version-stats-from-instapaper&quot;&gt;one of his regular iOS device and OS version stats overviews&lt;/a&gt; yesterday. While Marco’s stats obviously only represent Instapaper users and one has to be careful how representative the data is, these updates are nevertheless very welcome as they represent one of very few publicly available data points to estimate the adoption rate of iOS versions.&lt;/p&gt;

&lt;h1&gt;iOS 5 Adoption Rate Only at 45%&lt;/h1&gt;

&lt;p&gt;The most striking number to me is the rate of iOS 5 adoption: across Instapaper users on all iOS devices, 45% are running iOS 5. This strikes me as quite low. I would have expected a number in the range of 70–80%, especially considering that Instapaper users are probably significantly more geeky than the average iOS device owner.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h1&gt;How to Forcefully Exclude Older Devices From Running Your App&lt;/h1&gt;

&lt;p&gt;According to Marco’s numbers, having an app that requires iOS 5 would still exclude a lot of users at this time. Most developers should probably wait a least a few more months until they cut off iOS 4 support.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; For developers of apps that require a relatively high-performance device to run smoothly, that begs the question: how do I best restrict my app to only run on newer devices?&lt;/p&gt;

&lt;p&gt;It is important to implement such a restriction in a way that enforces it not only at runtime but also at install time. Otherwise, you will (rightfully) get lots of e-mail from angry iPhone 3G owners (if your app even makes it through the review process). Here are the options you have:&lt;/p&gt;

&lt;h2&gt;1. Require a Certain iOS Version&lt;/h2&gt;

&lt;p&gt;We just learned that it is probably too early to require iOS 5.0 but what about iOS 4.3? iOS 4.3 does not run on anything that’s older than the iPhone 3GS and it has an adoption rate of 88% in Marco’s stats. In fact, that is what Marco recommends:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Developers of CPU-intensive iPhone apps and games can celebrate the continued infiltration of faster hardware, with at-least-3GS-class CPUs in 94.39% of iPhones and iPod Touches. Apps that need high performance can probably start requiring iOS 4.3 (87.8%) to forcefully cut support for the much slower old CPU in the iPhone 1, iPhone 3G, and 1-2G iPod Touches.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;2. Require Certain Device Features such as OpenGL ES 2&lt;/h2&gt;

&lt;p&gt;If your app uses OpenGL ES 2, you are done because the GPUs in devices before the iPhone 3GS do not support that version. All you need to do is specify &lt;code&gt;opengles-2&lt;/code&gt; under the &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html#//apple_ref/doc/uid/TP40009252-SW3&quot;&gt;&lt;code&gt;UIRequiredDeviceCapabilities&lt;/code&gt;&lt;/a&gt; key in your &lt;code&gt;Info.plist&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;This is a convenient option but you should only use it if your app really uses and requires this special feature. Don’t just arbitrarily select a convenient option from the available device capabilities.&lt;/p&gt;

&lt;h2&gt;3. Require the armv7 CPU Architecture&lt;/h2&gt;

&lt;p&gt;One convenient way to sort of circumvent this rule is to explicitly require a device with a fast CPU: one of the options for &lt;code&gt;UIRequiredDeviceCapabilities&lt;/code&gt; is &lt;code&gt;armv7&lt;/code&gt;, which tells Apple and the OS that your app only runs on the modern CPU architecture that is used by the iPhone 3GS and all newer iOS devices. That way, you can allow iOS versions 4.0-4.2 and still restrict your app to modern hardware. (Please only do this if your app is really close to unusable on an iPhone 3G. Users of older hardware are probably used to somewhat slow performance, so they won’t necessarily hold it against you if your app stutters a bit.)&lt;/p&gt;

&lt;div class=&quot;with-caption&quot; style=&quot;width:466px&quot;&gt;
  &lt;p&gt;&lt;img src=&quot;/media/uirequireddevicecapabilities-armv7.png&quot; alt=&quot;Requiring the armv7 CPU architecture in the UIRequiredDeviceCapabilities key.&quot;&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;Requiring the armv7 CPU architecture in the UIRequiredDeviceCapabilities key.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Note: Patrick Burleson &lt;a href=&quot;http://twitter.com/pbur/status/142266546767671296&quot;&gt;noted on Twitter&lt;/a&gt; that he heard of app rejections when apps added new requirements to the &lt;code&gt;UIRequiredDeviceCapabilities&lt;/code&gt; in an update. I find it hard to believe that that is a general rule. It must be allowed for existing apps to switch to OpenGL ES 2.0, for example. But it’s probably good to keep in mind.&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;update&quot;&gt;&lt;strong&gt;Update December 23, 2011:&lt;/strong&gt; It seems indeed to be true that the required device capabilities cannot be changed in app updates. Please see &lt;a href=&quot;/blog/2011/12/uirequireddevicecapabilities-cannot-be-changed-in-app-updates/&quot;&gt;my follow-up post on the issue&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;It is not totally clear to me, however, how Marco arrived at these numbers. Do they represent a snapshot of his user base at the end of November? In that case, I would have expected the iOS 5 adoption rate to be much higher. Or is it an average across a longer period of time, perhaps the entire month or since the release of Instapaper 4.0? In that case, the 45% would not surprise me as much.&lt;a href=&quot;#fnref:1&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;That said, if I were to start developing a new app now, I would definitely go iOS 5 only.&lt;a href=&quot;#fnref:2&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2011/11/ios-and-mac-development-link-roundup-november-2011/</id>
    <title>iOS and Mac Development Link Roundup: November 2011</title>
    <published>2011-11-30T19:51:00Z</published>
    <updated>2011-12-01T14:55:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2011/11/ios-and-mac-development-link-roundup-november-2011/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2011/11/ios-and-mac-development-link-roundup-november-2011/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;I skipped my customary monthly link roundups in September and October simply because I did not have the time to compile them. Not only did the composition of the interesting links at the end of the month take up an increasing amount of time (which I would be fine with), but the fact that I felt I had to stay up to date with my Twitter timeline every single day in order not to miss anything made this impossible.&lt;/p&gt;

&lt;p&gt;Perhaps not surprisingly, the amount of positive feedback I got the roundups increased tremendously once I had stopped doing them. Thanks to everybody who told me they liked these posts. The feedback encouraged me to make another attempt at continuing the series, though note that I am not making any promises. It is quite possible that I abandon the whole thing again as soon as next month.&lt;/p&gt;

&lt;h1&gt;iOS 5.0.1&lt;/h1&gt;

&lt;p&gt;Apple &lt;a href=&quot;http://support.apple.com/kb/HT5052&quot;&gt;released iOS 5.0.1&lt;/a&gt;. The update contains, among other small improvements, a way for developers to specify files that should remain on device, even in low storage situations. iOS 5.0.1 thereby fixes &lt;a href=&quot;http://www.marco.org/2011/10/13/ios5-caches-cleaning&quot;&gt;the “Cleaning” issue faced by many offline content apps, illustrated by Marco Arment&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To prevent your offline files from both being backed up and deleted by the system, put them anywhere in your Documents or Library folder except &lt;code&gt;/Library/Caches&lt;/code&gt; and &lt;a href=&quot;http://developer.apple.com/library/ios/#qa/qa1719/_index.html&quot;&gt;set an extended attribute to mark them as “should not back up”&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks to Apple for providing such a quick fix. It shows that Apple is indeed willing to make changes to their policies when they realize the consequences for consumers are bad.&lt;/p&gt;

&lt;h1&gt;Programming&lt;/h1&gt;

&lt;h2&gt;Siri&lt;/h2&gt;

&lt;p&gt;The guys from Applidium &lt;a href=&quot;http://applidium.com/en/news/cracking_siri/&quot;&gt;reverse-engineered Siri’s protocol&lt;/a&gt;. Basically, Siri uses binary plists over a non-standard-conforming HTTPS to talk with the server. It seems to require an iPhone 4S device ID to authenticate against the server. The binary plists contain raw audio data using the Speex audio codec. Applidium also published a &lt;a href=&quot;https://github.com/applidium/Cracking-Siri&quot;&gt;collection of tool&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using these as a basis, someone named Pete created &lt;a href=&quot;https://github.com/plamoni/SiriProxy&quot;&gt;SiriProxy&lt;/a&gt;, a proxy server that allows you to inject custom handlers for certain keywords into Siri’s vocabular. &lt;a href=&quot;http://www.youtube.com/watch?v=AN6wy0keQqo&quot;&gt;Pete’s demo video&lt;/a&gt; is worth watching.&lt;/p&gt;

&lt;p&gt;In the meantime, several SiriProxy plugins have been published or demoed, such as &lt;a href=&quot;https://github.com/simonmaddox/SiriProxy/blob/fab7bb1798a40f2262f1c8a4970418b36f7825de/plugins/spotify/spotify.rb&quot;&gt;one for Spotify&lt;/a&gt; from Simon Maddox.&lt;/p&gt;

&lt;h2&gt;Components and Libraries&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://blog.mugunthkumar.com/products/ios-framework-introducing-mknetworkkit/&quot;&gt;MKNetworkKit&lt;/a&gt; by Mugunth Kumar is an interesting new iOS networking library, &lt;q&gt;inspired by&lt;/q&gt; both ASIHTTPRequest and AFNetworking.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://github.com/mattrajca/SVGKit&quot;&gt;SVGKit&lt;/a&gt; by Matt Rajca is a library for rendering SVG files as Core Animation layers. All shapes are represented by instances of the &lt;code&gt;CAShapeLayer&lt;/code&gt; class and are animatable.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://github.com/gmoledina/GMGridView&quot;&gt;GMGridView&lt;/a&gt; is a promising new grid view component for iOS, written by Gulam Moledina. Supports horizontal and vertical layouts, reordering via drag and drop, and the pinch-to-fullscreen gesture. Requires iOS 5.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Sam Vermette published &lt;a href=&quot;http://samvermette.com/309&quot;&gt;SVStatusHUD&lt;/a&gt;, a replica of Apple’s HUD overlays in iOS. I especially like how Sam prescribes the situations in which you should use the component to stay in accordance with Apple’s usage:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;It should only be used in response to hardware or other important notifications (for instance when an accessory is detected by your app).&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Matthijs Hollemans wrote &lt;a href=&quot;http://www.hollance.com/2011/11/mhtabbarcontroller-a-custom-tab-bar-for-ios-5-using-the-new-container-apis/&quot;&gt;MHTabBarController&lt;/a&gt;, a custom tab bar controller that illustrates the new view controller container APIs in iOS 5.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Tutorials and How Tos&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
    &lt;p&gt;Matthijs Hollemans has another nice trick up his sleeve: combine two JPEG images (the actual picture and a separate alpha mask) into &lt;a href=&quot;http://www.hollance.com/2011/11/transparent-jpeg-images/&quot;&gt;a single JPEG to make it transparent&lt;/a&gt;. Great for the rare case when a PNG file would be too large. Matthijs provides a simple &lt;code&gt;UIImage&lt;/code&gt; category that lets you do this.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The folks around Ray Wenderlich published &lt;a href=&quot;http://www.raywenderlich.com/tutorials&quot;&gt;multiple tutorials about some of the new iOS 5 features&lt;/a&gt;, such as Storyboards, ARC, and iCloud.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Keith Harrison shows &lt;a href=&quot;http://useyourloaf.com/blog/2011/11/16/mail-app-style-split-view-controller-with-a-sliding-master-v.html&quot;&gt;how to replicate the sliding master view of Mail.app&lt;/a&gt; in iOS 5. In a &lt;a href=&quot;http://useyourloaf.com/blog/2011/11/24/creating-gesture-recognizers-with-interface-builder.html&quot;&gt;follow-up post&lt;/a&gt;, Keith illustrates how to create the necessary gesture recognizers directly in Interface Builder. &lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Miscellaneous&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
    &lt;p&gt;The GNUstep project has release &lt;a href=&quot;http://lists.gnu.org/archive/html/discuss-gnustep/2011-11/msg00113.html&quot;&gt;version 1.6 of the GNUstep Objective-C Runtime&lt;/a&gt;, bringing it to a level with iOS 5.0 and OS X 10.7. The GNUstep runtime also includes an interesting feature: &lt;q&gt;Support for prototype-style object orientation&lt;/q&gt;, Javascript-style.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The LLVM team has started a series of posts outlining major changes in LLVM 3.0. So far, they have published two articles on &lt;a href=&quot;http://blog.llvm.org/2011/11/llvm-30-type-system-rewrite.html&quot;&gt;the type system rewrite&lt;/a&gt; and &lt;a href=&quot;http://blog.llvm.org/2011/11/llvm-30-exception-handling-redesign.html&quot;&gt;exception handling redesign&lt;/a&gt;. This is pretty in-depth stuff that you probably don’t need to know about but it never hurts to understand how the compiler works.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Martin Pilkington continued his series of Xcode reviews, &lt;a href=&quot;http://pilky.me/view/28&quot;&gt;this time with Xcode 4.2&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Nathan de Vries discovered &lt;a href=&quot;http://atnan.com/blog/2011/11/03/enabling-and-using-webgl-on-ios/?t=1320304062&quot;&gt;how to enable WebGL&lt;/a&gt; (which is publicly only available for iAds since iOS 4.2) in &lt;code&gt;UIWebView&lt;/code&gt; (using private APIs).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;An article titled &lt;a href=&quot;http://altdevblogaday.com/2011/11/22/parallel-implementations/&quot;&gt;Parallel Implementations&lt;/a&gt; by John Carmack:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;If the task you are working on can be expressed as a pure function that simply processes input parameters into a return structure, it is easy to switch it out for different implementations.  If it is a system that maintains internal state or has multiple entry points, you have to be a bit more careful about switching it in and out.  If it is a gnarly mess with lots of internal callouts to other systems to maintain parallel state changes, then you have some cleanup to do before trying a parallel implementation.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Daniel Jalkut in response to an &lt;a href=&quot;http://article.gmane.org/gmane.comp.version-control.git/57918&quot;&gt;old Linus Torvalds e-mail&lt;/a&gt; about his hatred of C++: &lt;a href=&quot;http://www.red-sweater.com/blog/2256/objective-c-is-the-language&quot;&gt;Objective-C is the Language&lt;/a&gt; &lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.readwriteweb.com/mobile/2011/11/crashalytics-knows-why-your-io.php&quot;&gt;Chrashalytics is a new contender in the iOS Crash Reporting field&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.vendorforge.org/&quot;&gt;VendorForge&lt;/a&gt; by Keith Pitt is one of several third-party package managers for Cocoa developers that popped up over the last few months. Other similar projects include &lt;a href=&quot;https://github.com/CocoaPods/CocoaPods&quot;&gt;CocoaPods&lt;/a&gt;, &lt;a href=&quot;https://github.com/nkpart/kit&quot;&gt;kit&lt;/a&gt; and &lt;a href=&quot;https://github.com/bazaarlabs/vendor&quot;&gt;vendor&lt;/a&gt;. Since managing third-party libraries in Xcode is currently an absolute pain, this is an area where the Cocoa community could really benefit. My hope is that we end up with one great package manager that everybody can agree upon instead of an ugly mess of multiple different approaches.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;h1&gt;Design&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
    &lt;p&gt;Wonderful article by Rob Beschizza at Boing Boing about the &lt;a href=&quot;http://boingboing.net/2011/11/14/what-the-vaio-z-says-about-son.html&quot;&gt;fundamental differences in the design approach of Apple and its competitors&lt;/a&gt;, namely Sony:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;Apple competitors are obsessed with copying Apple’s tastes without copying its central design habit, which is solving a problem and then refining the solution until the problem changes.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Former Apple employee Bret Victor published &lt;a href=&quot;http://worrydream.com/ABriefRantOnTheFutureOfInteractionDesign/&quot;&gt;A Brief Rant on the Future of Interaction Design&lt;/a&gt;, in which he encourages designers to not be satisfied with a future of &lt;q&gt;Pictures Under Glass&lt;/q&gt; (the touchscreen). The future of interaction should be &lt;q&gt;a dynamic medium that we can see, feel, and manipulate&lt;/q&gt;.&lt;/p&gt;

    &lt;p&gt;David Barnard replies: &lt;a href=&quot;http://appcubby.com/blog/pictures-under-glass/&quot;&gt;“Pictures Under Glass” is Revolutionary, Not Transitional&lt;/a&gt;:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;My 2 year old son, Luke, is incredibly adept at using the iPad precisely because it doesn’t require tactile feedback to master, not in-spite of it.&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;p&gt;To Edward Tufte, Victor’s essay is &lt;a href=&quot;http://www.edwardtufte.com/bboard/q-and-a-fetch-msg?msg_id=0003qM&amp;amp;topic_id=1&quot;&gt;&lt;q&gt;a celebration of the hand rather than about interface possibilities&lt;/q&gt;&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Andy Mangold &lt;a href=&quot;http://www.andymangold.com/skeuomorphism-the-opiate-of-the-people/&quot;&gt;sees skeuomorphism as &lt;q&gt;the opiate of the people&lt;/q&gt; &lt;/a&gt; and argues that’s the underlying reason for the recent trend towards skeuomorphism in UI design:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;But what hadn’t occurred to me is that it doesn’t matter if it actually does make it easier to use, all that matters is that it makes the average person &lt;em&gt;think&lt;/em&gt; it’s easier to use.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Devin Coldewey: &lt;a href=&quot;http://techcrunch.com/2011/11/11/in-defense-of-the-stylus/&quot;&gt;In Defense of the Stylus&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://mobiledesignpatterngallery.com/mobile-patterns.php&quot;&gt;Mobile Design Pattern Gallery&lt;/a&gt; is another one of those sites that collect design patterns for mobile apps and examples of successful implementations. Looks good. Oliver Drobnik has compiled &lt;a href=&quot;http://www.cocoanetics.com/2011/11/steal-good-stuff-ios-design-pattern-collections/&quot;&gt;a list of similar sites showcasing design patterns or outstanding app designs&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;h1&gt;Community&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
    &lt;p&gt;Charlie Miller found a serious security hole in iOS &lt;a href=&quot;http://www.forbes.com/sites/andygreenberg/2011/11/07/iphone-security-bug-lets-innocent-looking-apps-go-bad/&quot;&gt;that allows apps to download code and execute it outside of their sandbox&lt;/a&gt;. The result: Apple removed the offending demo app from the App Store and threw Charlie Miller out of the developer program &lt;a href=&quot;http://twitter.com/0xcharlie/status/133898695384109056&quot;&gt;for 1 year&lt;/a&gt;. Federico Viticci &lt;a href=&quot;http://www.macstories.net/news/security-researcher-demoes-bug-to-execute-unsigned-code-on-ios-devices/&quot;&gt;wrote about it for MacStories&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Chris Schilling did a &lt;a href=&quot;http://recombu.com/news/interview-ustwos-mills-on-whale-trail-the-rise-of-freemium-and-the-death-of-69p-gaming_M15758.html&quot;&gt;fantastic interview with Matt Mills of ustwo&lt;/a&gt;, creators of Whale Trail. So much insight about the state of the App Store and the game industry in this one. (Their &lt;a href=&quot;http://www.youtube.com/watch?v=r8bJs8opqRw&quot;&gt;Making of Whale Trail&lt;/a&gt; video is also worth watching.)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://mattgemmell.com/2011/11/27/copycats/&quot;&gt;Copycats&lt;/a&gt; is a great article by Matt Gemmell:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;There’s nothing new under the sun, as they say - we’re all inspired and affected by other things. All of our design takes place under constraints. So, be influenced. Incorporate elements. Agree with implementations. Understand an approach. Realise the purpose and function of a design decision. Address a need. &lt;em&gt;Renew something.&lt;/em&gt; Be an innovator, not a copycat.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;David Barnard talks openly about &lt;a href=&quot;http://appcubby.com/blog/the-dreaded-app-store-fizzle/&quot;&gt;the rather disappointing launch of this beautiful new app&lt;/a&gt;, TweetSpeaker.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The guys from Shifty Jelly wrote a post that describes pretty well &lt;a href=&quot;http://shiftyjelly.wordpress.com/2011/11/22/you-guys-are-millionaires-right/&quot;&gt;how life is as an indie developer&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;In &lt;a href=&quot;http://wildchocolate.tumblr.com/post/12555879965/a-letter-to-the-developer-community&quot;&gt;A Letter to the Developer Community&lt;/a&gt;, Brittany Tarvin raises an important problem: what can we all do to make women feel more welcome in this community? For example, at Apple’s iOS 5 Tech Talk in Berlin this month, less than 1% of the participants were women. It felt just wrong, regardless if you were a man or a woman.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://cycle-gap.blogspot.com/2011/11/john-gruber-has-some-career-advice-for.html&quot;&gt;Great, encouraging quote from John Gruber’s keynote speech at the Çingleton Symposium&lt;/a&gt; in October: &lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;If you think this app store platform is big now, you really haven’t seen anything yet. … But I say to you, “This is an extraordinary time to be an Apple developer”. This is the right time and the right place. This is a once in a career opportunity. … If things go right, if things go the way I think they are going to go, these next five years, we are never going to work harder, we are never going to be under more pressure, we’re never going to be more stressed, we are never going to feel like we have to work faster and we are never going to have to solve tougher problems. We’re never going to have to move this fast. But the only thing any of us are going to regret is if we don’t aim big enough.&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;p&gt;The whole talk is worth watching.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;h1&gt;App Store&lt;/h1&gt;

&lt;h2&gt;Sandboxing Deadline Extended&lt;/h2&gt;

&lt;p&gt;Apple extended its deadline for Mac App Store apps to be sandboxed &lt;a href=&quot;http://developer.apple.com/news/index.php?id=11022011a&quot;&gt;from the planned November 2011 to March 1, 2012&lt;/a&gt;. The nearer the original deadline came, realization probably grew in Cupertino that developers need more time to assess the impact of the sandboxing requirements on their apps and adapt them accordingly. And hopefully, Apple provides enough leeway to allow Mac apps to exist under sandboxing without impairing functionality that users take for granted.&lt;/p&gt;

&lt;p&gt;On the occasion of Apple’s announcement, an interesting discussion about the merits (or not) of sandboxing sprung up in the blogosphere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
    &lt;p&gt;Wil Shipley wrote a long article about the &lt;a href=&quot;http://blog.wilshipley.com/2011/11/real-security-in-mac-os-x-requires.html&quot;&gt;benefits and drawbacks of sandboxing and other security measures such as code signing and code review&lt;/a&gt;. Wil concludes that sandboxing is not the right way and suggests that Lion only run code signed by an Apple certificate. At first, Apple would allow any developer to sign code with their certificate, but could then revoke it on a per-developer basis in case of a security problem.&lt;/p&gt;

    &lt;p&gt;It’s an interesting idea and I certainly concur that Apple’s sandboxing model is not a good measure against malware. I’d add, however, that sandboxing has other merits, e.g. in the field of privacy.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Pauli Olavi Ojala makes &lt;a href=&quot;http://lacquer.fi/pauli/blog/2011/11/why-the-mac-app-sandbox-makes-me-sad/&quot;&gt;a very convincing case against sandboxing&lt;/a&gt; from a functionality perspective: it seems to mean the end of app plugins.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;John Martellaro from The Mac Observer interviews MarsEdit developer Daniel Jalkut about &lt;a href=&quot;http://www.macobserver.com/tmo/article/developer_losing_control_of_our_destiny_to_apple/&quot;&gt;his opinion on the Mac App Store and especially sandboxing&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Pricing and Marketing&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
    &lt;p&gt;Oliver Reichenstein &lt;a href=&quot;https://plus.google.com/115711522874757126523/posts/LwZyWLKLN94&quot;&gt;experimented with the pricing for iA Writer on iPad and Mac&lt;/a&gt;: &lt;q&gt;No matter what price we choose, we always make the same revenue.&lt;/q&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://nathanbarry.com/how-i-made-19000-on-the-app-store-while-learning-to-code/&quot;&gt;Great story by Nathan Barry&lt;/a&gt; how you can make money on the App Store not only without prior programming knowledge but also with a high-priced niche product.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Ben Rooney reports on a talk by Greg Joswiak, part of the product marketing team at Apple, about &lt;a href=&quot;http://blogs.wsj.com/tech-europe/2011/11/18/four-keys-to-apples-success/&quot;&gt;four keys to Apple’s success&lt;/a&gt;: &lt;q&gt;Focus, Simplicity, Courage, Best&lt;/q&gt;. There is a lot of great quotes in this short piece.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Nicholas Lovell about the tendency of the gaming market towards free: &lt;a href=&quot;http://www.gamasutra.com/view/news/38502/Opinion_Who_Will_Survive_The_Digital_Tsunami.php&quot;&gt;Who Will Survive the Digital Tsunami?&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;King Sidharth wrote a good post called &lt;a href=&quot;http://www.64notes.com/app-vs-business/&quot;&gt;Apps vs. Business&lt;/a&gt;. It takes more than just a good app to take down another business. You need to create a business: &lt;q&gt;Solve a problem, then sell the solution&lt;/q&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Confusion of the month: some company &lt;a href=&quot;http://www.bloomberg.com/news/2011-11-22/apple-lets-big-fish-games-offer-ipad-subscription-a-first-for-video-games.html&quot;&gt;announced that Apple approved a subscription-based gaming app&lt;/a&gt; but &lt;a href=&quot;http://www.bloomberg.com/news/2011-11-23/apple-removes-big-fish-s-game-subscription-plan-from-app-store.html&quot;&gt;Apple quickly removed it from the App Store&lt;/a&gt;. Probably just a mistake by an app reviewer.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Laugh of the month: Rich Jones reports that &lt;a href=&quot;http://gun.io/blog/the-governments-200000-useless-android-application/&quot;&gt;the US government apparently paid $200,000 to have an absolute piece of crap app developed&lt;/a&gt; (for three mobile platforms). Take a look at &lt;a href=&quot;http://www.osha.gov/SLTC/heatillness/heat_index/heat_app.html&quot;&gt;the source code&lt;/a&gt; yourself.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;div class=&quot;update&quot;&gt;
  &lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Update December 1, 2011:&lt;/strong&gt; Marco Arment updated his regular &lt;a href=&quot;http://www.marco.org/2011/11/30/more-ios-device-and-os-version-stats-from-instapaper&quot;&gt;device and OS version stats&lt;/a&gt;. As of the end of November, 45% of Instapaper users have updated to iOS 5. I would have expected a higher adoption rate.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;h1&gt;Competition&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
    &lt;p&gt;Adobe finally &lt;a href=&quot;http://blogs.adobe.com/conversations/2011/11/flash-focus.html&quot;&gt;kills the Mobile Flash Player&lt;/a&gt;. Opinions on the decision:&lt;/p&gt;

    &lt;ul&gt;
&lt;li&gt;
        &lt;p&gt;John Gruber: &lt;a href=&quot;http://daringfireball.net/linked/2011/11/09/everybody-wins&quot;&gt;Everybody wins&lt;/a&gt;.&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Matt Drance: &lt;a href=&quot;http://www.appleoutsider.com/2011/11/09/falsh/&quot;&gt;It is a victory for Adobe&lt;/a&gt;.&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Apple Insider reports &lt;a href=&quot;http://www.appleinsider.com/articles/11/11/21/googles_android_market_estimated_to_earn_just_7_of_what_apples_app_store_makes.html&quot;&gt;an estimate by Piper Jaffray analyst Gene Munster&lt;/a&gt; saying that the Android Market has generated only 7% of the revenue that Apple’s App Store has made since its inception. This analysis is flawed on so many levels (different launch dates of the two stores; is the Mac App Store included?) that it is hard for me to believe in the numbers, though.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Related to this, Ben Brooks attempts an explanation &lt;a href=&quot;http://brooksreview.net/2011/11/apps-android/&quot;&gt;&lt;q&gt;why Android developers don’t make great looking apps&lt;/q&gt;&lt;/a&gt; – generally speaking.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Jay Greene from CNET with the story &lt;a href=&quot;http://news.cnet.com/8301-10805_3-20128013-75/the-inside-story-of-how-microsoft-killed-its-courier-tablet/&quot;&gt;how and why Microsoft killed its promising Courier tablet&lt;/a&gt;. I still think this thing could have been a hit.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://groups.google.com/forum/#!msg/android-building/T4XZJCZnqF8/WkWhGUYb4MAJ&quot;&gt;Google released the source code for Android 4.0&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Nathan de Vries explains the &lt;a href=&quot;http://atnan.com/blog/2011/11/10/ios-vs-android-ics-hardware-accelerated-graphics-pipelines/&quot;&gt;improvements that Android 4.0 made in its rendering pipeline&lt;/a&gt;, which should bring graphics performance into the same league as iOS and Windows Phone.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;&lt;h1&gt;Steve Jobs Biography&lt;/h1&gt;

&lt;p&gt;Walter Isaacson’s Steve Jobs biography came out in late October and many of you have probably already read the book. If you haven’t, I think you should do so because it really is quite good (although probably not as good as it could and should have been).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
    &lt;p&gt;In episodes &lt;a href=&quot;http://5by5.tv/hypercritical/42&quot;&gt;42&lt;/a&gt; and &lt;a href=&quot;http://5by5.tv/hypercritical/43&quot;&gt;43&lt;/a&gt; of the Hypercritical podcast, John Siracusa makes some very strong and well-founded arguments against the book and its author: &lt;q&gt;Jobs picked the wrong guy&lt;/q&gt;. The podcasts are not short but if you make the effort to read the book, I think you should also listen to these episodes, it’s worth it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Jean-Louis Gassée &lt;a href=&quot;http://www.mondaynote.com/2011/10/30/steve%E2%80%99s-bio-a-personal-perspective/&quot;&gt;reviews the Jobs biography from his insider perspective&lt;/a&gt; as one of the top Apple employees in the post-Jobs era.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A recent Churchill Club &lt;a href=&quot;http://www.youtube.com/watch?v=N2C2oCsrqcM&quot;&gt;panel about Steve Jobs’s Legacy&lt;/a&gt; is a very good companion to the book. The panel’s participants Bill Atkinson, Jean-Louis Gassée, Andy Hertzfeld, Regis McKenna, Deborah Stapleton, Larry Tesler are some of the people you also get to know in the early chapters of the biography.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;John Gruber, criticizing &lt;a href=&quot;http://www.newyorker.com/reporting/2011/11/14/111114fa_fact_gladwell?currentPage=all&quot;&gt;Malcom Gladwell’s take on Jobs’s personality&lt;/a&gt;: &lt;a href=&quot;http://daringfireball.net/2011/11/getting_steve_jobs_wrong&quot;&gt;Getting Steve Jobs Wrong&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Nick Bilton did a &lt;a href=&quot;http://bits.blogs.nytimes.com/2011/11/18/one-on-one-walter-isaacson-biographer-of-steve-jobs/&quot;&gt;short interview with Walter Isaacson&lt;/a&gt; about the book.&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;He had three things that he wanted to reinvent: the television, textbooks and photography. He really wanted to take these on.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Luke Wroblewski: &lt;a href=&quot;http://www.lukew.com/ff/entry.asp?1449&quot;&gt;Memorable quotes from Robert X. Cringely’s rediscovered 1995 interview with Steve Jobs&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2011/11/date-and-time-in-cocoa-cheat-sheet/</id>
    <title>Date and Time Handling in Cocoa Cheat Sheet</title>
    <published>2011-11-23T18:00:00Z</published>
    <updated>2011-11-23T18:00:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2011/11/date-and-time-in-cocoa-cheat-sheet/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2011/11/date-and-time-in-cocoa-cheat-sheet/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;As a conclusion of my little series about date and time handling in Cocoa, I have prepared this cheat sheet that lists the participating classes, their main tasks and interrelations:&lt;/p&gt;

&lt;div class=&quot;with-caption&quot; style=&quot;width:660px&quot;&gt;
  &lt;p&gt;&lt;a href=&quot;/media/date-and-time-in-cocoa-cheatsheet.png&quot; class=&quot;img-link&quot;&gt;&lt;img src=&quot;/media/date-and-time-in-cocoa-cheatsheet-660px.png&quot; alt=&quot;Date and Time Handling in Cocoa Cheat Sheet: NSDate, NSDateComponents, NSDateFormatter, NSDataDetector, NSCalendar, NSTimeZone and NSLocale.&quot;&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p class=&quot;caption&quot;&gt;Date and Time Handling in Cocoa Cheat Sheet: NSDate, NSDateComponents, NSDateFormatter, NSDataDetector, NSCalendar, NSTimeZone and NSLocale.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;/media/DateTimeHandlingInCocoaCheatSheet.pdf&quot;&gt;Download the cheat sheet as PDF&lt;/a&gt;.&lt;/p&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2011/11/working-with-date-and-time-in-cocoa-part-2/</id>
    <title>Working with Date and Time in Cocoa (Part 2)</title>
    <published>2011-11-22T21:58:00Z</published>
    <updated>2011-11-23T10:44:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2011/11/working-with-date-and-time-in-cocoa-part-2/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2011/11/working-with-date-and-time-in-cocoa-part-2/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;In part 2 of my little series on date and time handling in Cocoa I am going to talk about date parsing and formatting. In other words: how to convert strings into date objects and vice versa. You should &lt;a href=&quot;/blog/2011/11/working-with-date-and-time-in-cocoa-part-1/&quot;&gt;read part 1 first&lt;/a&gt; if you haven’t yet to get an overview of the classes used by Cocoa’s date and time system.&lt;/p&gt;

&lt;h1&gt;NSDateFormatter&lt;/h1&gt;

&lt;p&gt;When working with date and time, two very common requirements are, (1) displaying dates in your UI, and (2) reading in date/time values from external sources like a web service or text file. Since humans are not very good at interpreting the second-based timestamps that &lt;code&gt;NSDate&lt;/code&gt; uses to store dates internally, both of these tasks usually make it necessary to convert between &lt;code&gt;NSDate&lt;/code&gt; and &lt;code&gt;NSString&lt;/code&gt; or vice versa.&lt;/p&gt;

&lt;p&gt;In the Foundation framework, the class to use for this task (in either direction) is &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003643&quot;&gt;&lt;code&gt;NSDateFormatter&lt;/code&gt;&lt;/a&gt;. Let me show you how it works.&lt;/p&gt;

&lt;h1&gt;1. Turning Dates Into Strings&lt;/h1&gt;

&lt;p&gt;Let’s start with the easier (because less error-prone) of the two directions: turn an &lt;code&gt;NSDate&lt;/code&gt; instance into a readable string. Usage of the &lt;code&gt;NSDateFormatter&lt;/code&gt; class always involves three steps: (1) create the date formatter; (2) configure it; (3) send it a &lt;code&gt;stringFromDate:&lt;/code&gt; message to get the result. Obviously, the configuration step is where the interesting stuff happens. We should differentiate between two separate use cases: do we want to create a human-readable output or do we need to create a string according to a specific format to be read by another API?&lt;/p&gt;

&lt;h2&gt;Formatting for Humans: Let the User Decide&lt;/h2&gt;

&lt;p&gt;When displaying dates in your app’s UI, you should always take the user’s preferences into account. Fortunately, that is easy with &lt;code&gt;NSDateFormatter&lt;/code&gt;. To simply convert an &lt;code&gt;NSDate&lt;/code&gt; into an &lt;code&gt;NSString&lt;/code&gt; use code like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;myDate &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSDate date&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSDateFormatter &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateFormatter &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSDateFormatter alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateFormatter setDateStyle&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSDateFormatterMediumStyle&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateFormatter setTimeStyle&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSDateFormatterMediumStyle&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSString &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;myDateString &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;dateFormatter stringFromDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;myDate&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl kwd&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;%@&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; myDateString&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With my current locale settings (German), the output looks like this: &lt;code&gt;22.11.2011 18:33:19&lt;/code&gt;, but that’s just me. By default, &lt;code&gt;NSDateFormatter&lt;/code&gt; observes the current user’s locale settings so other users might see results like &lt;code&gt;Nov 22, 2011 6:33:19 PM&lt;/code&gt; or &lt;code&gt;2011-11-22 下午6:33:19&lt;/code&gt; or even &lt;code&gt;२२-११-२०११ ६:३३:१९ अपराह्&lt;/code&gt;, all for the same input and with the same code.&lt;/p&gt;

&lt;p&gt;As a developer, you are not supposed to care about the actual output. Just use the &lt;code&gt;setDateStyle:&lt;/code&gt; and &lt;code&gt;setTimeStyle:&lt;/code&gt; methods to control how short or long the output should be. Possible values are &lt;code&gt;NSDateFormatterShortStyle&lt;/code&gt;, &lt;code&gt;NSDateFormatterMediumStyle&lt;/code&gt;, &lt;code&gt;NSDateFormatterLongStyle&lt;/code&gt; and &lt;code&gt;NSDateFormatterFullStyle&lt;/code&gt;; you can also use &lt;code&gt;NSDateFormatterNoStyle&lt;/code&gt; to suppress the date or the time component in the resulting string.&lt;/p&gt;

&lt;p&gt;The class method &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/Reference/Reference.html#//apple_ref/doc/uid/20000447-SW52&quot;&gt;&lt;code&gt;+localizedStringFromDate:dateStyle:timeStyle:&lt;/code&gt;&lt;/a&gt; provides a shorter way to achieve the same result as the code snippet above.&lt;/p&gt;

&lt;p&gt;If you want to have more control over the output format, you can set a specific format using the &lt;code&gt;setDateFormat:&lt;/code&gt; method. Note, though, that Apple specifically discourages that approach for human-readable dates since there is no date and time format that is accepted worldwide. &lt;code&gt;NSDateFormatter&lt;/code&gt; understands the date format specifiers of the &lt;a href=&quot;http://unicode.org/reports/tr35/tr35-10.html#Date_Format_Patterns&quot;&gt;Unicode spec for date formats&lt;/a&gt;. If you want to go this route, have a look at the &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/Reference/Reference.html#//apple_ref/doc/uid/20000447-SW53&quot;&gt;&lt;code&gt;+dateFormatFromTemplate:options:locale:&lt;/code&gt;&lt;/a&gt; class method. It lets you specify a string of date format specifiers that your output string should include and returns an appropriate date format string for the specified locale.&lt;/p&gt;

&lt;h2&gt;Formatting for Machines: Controlled Environment Needed&lt;/h2&gt;

&lt;p&gt;It is a whole other matter if you need to create a date string according to the specification of a certain file format or API. In such a case, you usually have to follow a very strict spec to make sure the other party can read the string you are generating.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;It should be clear that we must use the &lt;code&gt;setDateFormat:&lt;/code&gt; method here. But that is not enough. Remember from &lt;a href=&quot;/blog/2011/11/working-with-date-and-time-in-cocoa-part-1/&quot;&gt;part 1&lt;/a&gt; that you can represent the same point in time very differently, depending on the calendar and time zone. By default, &lt;code&gt;NSDateFormatter&lt;/code&gt; uses the user’s current calendar and time zone, which are possibly different from the requirements. Most file formats and web APIs use the western, Gregorian calendar, so we need to make sure that our date formatter uses it, too:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;myDate &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSDate dateWithTimeIntervalSinceReferenceDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;343675999.713839&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSDateFormatter &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateFormatter &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSDateFormatter alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSCalendar &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;calendar &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSCalendar alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithCalendarIdentifier&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSGregorianCalendar&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateFormatter setCalendar&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;calendar&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We must also make sure to set the date formatter’s &lt;em&gt;locale&lt;/em&gt; to a generic value so as not to run into conflict’s with the user’s locale settings, which can influence the naming of weekdays and months as well as the clocks 12/24 hour setting. The date formatter’s &lt;code&gt;setLocale:&lt;/code&gt; method expects an instance of the &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSLocale_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003674&quot;&gt;&lt;code&gt;NSLocale&lt;/code&gt;&lt;/a&gt; class. To create one, we need to specify a locale identifiers. These usually consist of a combination of a language and a country code, such as &lt;code&gt;@&quot;en_US&quot;&lt;/code&gt;. For our needs, however, there exists the special locale identifier &lt;code&gt;@&quot;en_US_POSIX&quot;&lt;/code&gt; that is &lt;a href=&quot;http://developer.apple.com/library/ios/#qa/qa1480/_index.html&quot;&gt;guaranteed to not change in the future&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note that a locale also includes a calendar setting so setting the calendar explicitly as we did above is no longer necessary (but does not hurt).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;NSLocale &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;locale &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSLocale alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithLocaleIdentifier&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;en_US_POSIX&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateFormatter setLocale&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;locale&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The date’s time zone can possibly be included in the formatted output string. But as I also mentioned in &lt;a href=&quot;/blog/2011/11/working-with-date-and-time-in-cocoa-part-1/&quot;&gt;part 1&lt;/a&gt;, time zone identifiers such as “+01:00”, “PST” or “CET” are notoriously ambiguous. In most cases, it’s best to stick with UTC:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;NSTimeZone &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;timeZone &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSTimeZone timeZoneForSecondsFromGMT&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateFormatter setTimeZone&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;timeZone&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, we are finally ready to set our date format and create the result string. For example, to format a date according to the common &lt;a href=&quot;http://www.ietf.org/rfc/rfc3339.txt&quot;&gt;RFC 3339&lt;/a&gt; (&lt;a href=&quot;http://en.wikipedia.org/wiki/ISO_8601&quot;&gt;ISO 8601&lt;/a&gt;) standard:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateFormatter setDateFormat&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSString &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;myDateString &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;dateFormatter stringFromDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;myDate&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl slc&quot;&gt;// =&amp;gt; 2011-11-22T17:33:19Z&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Again, see the &lt;a href=&quot;http://unicode.org/reports/tr35/tr35-10.html#Date_Format_Patterns&quot;&gt;Unicode standard mentioned above&lt;/a&gt; for a list of possible format specifiers. Pay special attention to the year format specifier &lt;code&gt;@&quot;yyyy&quot;&lt;/code&gt;. It is different than the capitalized &lt;code&gt;@YYYY&lt;/code&gt;, which represents the year of the date’s week and not the year of the day. 99% of the time, you probably want to use @”yyyy”. I have seen this bug so many times in production code that it’s not funny anymore so make sure your unit tests catch it.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Also note that I am using the literal character &lt;code&gt;'Z'&lt;/code&gt; to represent the UTC time zone we set on the date formatter before. If you need to include the time zone in your format string, make sure to experiment with the possible time zone format specifiers (&lt;code&gt;z&lt;/code&gt;, &lt;code&gt;Z&lt;/code&gt;, &lt;code&gt;v&lt;/code&gt;, &lt;code&gt;V&lt;/code&gt;, each with 1-4 characters) and different time zones to really understand what you’re getting yourself into.&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; As I said, dealing with time zones is no fun, especially when it comes to ambiguous abbreviations or daylight savings time. It’s best to avoid if at all possible.&lt;/p&gt;

&lt;h1&gt;2. Turning Strings Into Dates&lt;/h1&gt;

&lt;p&gt;Let’s move on to the other side of &lt;code&gt;NSDateFormatter&lt;/code&gt;: parsing a string representation of a date and/or time and converting it to an &lt;code&gt;NSDate&lt;/code&gt; instance. Your main use case for this should be the parsing of dates you read in from a web service API or a text file.&lt;/p&gt;

&lt;h2&gt;Parsing Machine-Generated Dates&lt;/h2&gt;

&lt;p&gt;In this case, you use the class much like in the reverse case that we just discussed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an &lt;code&gt;NSDateFormatter&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Create a controlled environment by setting the formatter’s locale and possibly time zone as specified by the input format. In most cases, this means the &lt;code&gt;en_US_POSIX&lt;/code&gt; locale and the UTC time zone.&lt;/li&gt;
  &lt;li&gt;Set the formatter’s date format string to the specified format.&lt;/li&gt;
  &lt;li&gt;Call &lt;code&gt;dateFromString:&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;For example, here is how to parse a date from an RSS feed entry of the form &lt;code&gt;Mon, 06 Sep 2009 16:45:00 -0900&lt;/code&gt; as specified in &lt;a href=&quot;http://www.faqs.org/rfcs/rfc822.html&quot;&gt;RFC 822&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;NSString &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;myDateString &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; @&lt;span class=&quot;hl str&quot;&gt;&quot;Mon, 06 Sep 2009 16:45:00 -0900&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;

NSDateFormatter &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateFormatter &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSDateFormatter alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSLocale &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;locale &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSLocale alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithLocaleIdentifier&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;en_US_POSIX&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateFormatter setLocale&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;locale&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateFormatter setDateFormat&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;EEE, dd MMM yyyy HH:mm:ss Z&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;

NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;myDate &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;dateFormatter dateFromString&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;myDateString&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl kwd&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;%@&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; myDate&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;hl slc&quot;&gt;// =&amp;gt; 2009-09-07 01:45:00 +0000&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note how we did not set the date formatter’s time zone explicitly here. Instead, the &lt;code&gt;Z&lt;/code&gt; character in the format string is now a format specifier for the time zone rather than the literal character it was in the example above. Also note that the output format of &lt;code&gt;NSLog()&lt;/code&gt; shows date and time in UTC but it really represents the exact same point in time as the input string.&lt;/p&gt;

&lt;p&gt;If a date formatter cannot parse the string, &lt;code&gt;dateFromString:&lt;/code&gt; returns &lt;code&gt;nil&lt;/code&gt;. Your code must be able to deal with this case gracefully.&lt;/p&gt;

&lt;h2&gt;Parsing Free-Form Date Strings&lt;/h2&gt;

&lt;p&gt;What if you don’t know the exact format of the string, e.g. because you want to let the user enter a date and time in a free-form text field&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;? I am afraid that &lt;code&gt;NSDateFormatter&lt;/code&gt; will probably not be a big help then. The class does have a &lt;code&gt;setLenient:&lt;/code&gt; method that enables heuristics when parsing a string. However, even in lenient mode you are still required to specify an exact date format. In lenient mode, the formatter correctly parses a date string containing slashes (&lt;code&gt;@&quot;03/11/2011 11:03:45&quot;&lt;/code&gt;) when the date format specifies blanks (&lt;code&gt;@&quot;dd MMM yyyy HH:mm:ss&quot;&lt;/code&gt;) but that seems approximately to be the extent of what it can do.&lt;/p&gt;

&lt;p&gt;For really lenient parsing with &lt;code&gt;NSDateFormatter&lt;/code&gt;, you would probably have to try multiple formats and check for success after each attempt. The Unicode standard includes some &lt;a href=&quot;http://unicode.org/reports/tr35/tr35-10.html#Lenient_Parsing&quot;&gt;suggestions for lenient parsing&lt;/a&gt; if you want to go that route.&lt;/p&gt;

&lt;p class=&quot;update&quot;&gt;&lt;strong&gt;Update November 23, 2011:&lt;/strong&gt; In most cases, you are probably better off providing the user a dedicated control for date and time entry that guarantees valid and unambiguous values, such as &lt;a href=&quot;http://developer.apple.com/library/ios/#documentation/uikit/reference/UIDatePicker_Class/Reference/UIDatePicker.html&quot;&gt;&lt;code&gt;UIDatePicker&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSDatePicker_Class/Reference/Reference.html&quot;&gt;&lt;code&gt;NSDatePicker&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;NSDataDetector to the Rescue!&lt;/h3&gt;

&lt;p&gt;A more promising approach might be the relatively new &lt;a href=&quot;http://developer.apple.com/library/ios/#documentation/Foundation/Reference/NSDataDetector_Class/Reference/Reference.html&quot;&gt;&lt;code&gt;NSDataDetector&lt;/code&gt;&lt;/a&gt; class. Although not a classic member of the date and time handling classes in Cocoa, I want to mention it here for its ability to match, among other things, dates and times in free-form strings such as e-mail messages.&lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;NSDataDetector&lt;/code&gt; is a special kind of regular expression, its API is completely different:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;NSString &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;myDateString &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; @&lt;span class=&quot;hl str&quot;&gt;&quot;24.11.2011 15:00&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
NSError &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;error &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl kwa&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
NSDataDetector &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;detector &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSDataDetector dataDetectorWithTypes&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSTextCheckingTypeDate error&lt;span class=&quot;hl opt&quot;&gt;:&amp;amp;&lt;/span&gt;error&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSArray &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;matches &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;detector matchesInString&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;myDateString options&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;0&lt;/span&gt; range&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl kwd&quot;&gt;NSMakeRange&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;, [&lt;/span&gt;myDateString length&lt;span class=&quot;hl opt&quot;&gt;])];&lt;/span&gt;
&lt;span class=&quot;hl kwa&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;NSTextCheckingResult &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;match &lt;span class=&quot;hl kwa&quot;&gt;in&lt;/span&gt; matches&lt;span class=&quot;hl opt&quot;&gt;) {&lt;/span&gt;
    &lt;span class=&quot;hl kwd&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;Detected Date: %@&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; match.date&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;           &lt;span class=&quot;hl slc&quot;&gt;// =&amp;gt; 2011-11-24 14:00:00 +0000&lt;/span&gt;
    &lt;span class=&quot;hl kwd&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;Detected Time Zone: %@&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; match.timeZone&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;hl slc&quot;&gt;// =&amp;gt; (null)&lt;/span&gt;
    &lt;span class=&quot;hl kwd&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;Detected Duration: %f&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; match.duration&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;   &lt;span class=&quot;hl slc&quot;&gt;// =&amp;gt; 0.000000&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this case, the detection worked great&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;, and the detector can also deal with relative strings such as &lt;code&gt;@&quot;next Monday at 7 pm&quot;&lt;/code&gt; or &lt;code&gt;@&quot;tomorrow at noon&quot;&lt;/code&gt;. &lt;code&gt;NSDataDetector&lt;/code&gt; always seems to use the current locale and time zone to interpret dates in strings.&lt;/p&gt;

&lt;h1&gt;Miscellaneous Findings&lt;/h1&gt;

&lt;h2&gt;Use Thread-Local Storage for NSDateFormatter&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;-[NSDateFormatter init]&lt;/code&gt; method is quite expensive. If you need the same date formatter repeatedly, you should cache it, either in a static variable &lt;a href=&quot;http://developer.apple.com/library/ios/#qa/qa1480/_index.html&quot;&gt;as in this example in Apple’s Technical Q&amp;amp;A QA1480&lt;/a&gt; (see Listing 2) or, even better, by using &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/10000057i-CH15-SW4&quot;&gt;Thread-Local Storage&lt;/a&gt; as explained by Alex Curylo in his article &lt;a href=&quot;http://www.alexcurylo.com/blog/2011/07/05/threadsafe-date-formatting/&quot;&gt;Threadsafe Date Formatting&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;More Efficient Date Parsing&lt;/h2&gt;

&lt;p&gt;If you still encounter performance problems with &lt;code&gt;NSDateFormatter&lt;/code&gt;, note this suggestion in the same &lt;a href=&quot;http://developer.apple.com/library/ios/#qa/qa1480/_index.html&quot;&gt;QA1480&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Finally, if you’re willing to look at solutions outside of the Cocoa space, it’s very easy and efficient to parse and generate fixed-format dates using the standard C library functions &lt;a href=&quot;http://developer.apple.com/library/mac/#documentation/darwin/reference/manpages/man3/strptime_l.3.html&quot;&gt;&lt;code&gt;strptime_l&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;http://developer.apple.com/library/mac/#documentation/darwin/reference/manpages/man3/strftime_l.3.html&quot;&gt;&lt;code&gt;strftime_l&lt;/code&gt;&lt;/a&gt;. Be aware that the C library also has the idea of a current locale. To guarantee a fixed date format, you should pass &lt;code&gt;NULL&lt;/code&gt; to the &lt;code&gt;loc&lt;/code&gt; parameter of these routines. This causes them to use the POSIX locale (also known as the C locale), which is equivalent to Cocoa’s “en_US_POSIX” locale.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For a data point, see Sam Soffes’s article how he &lt;a href=&quot;http://samsoff.es/posts/how-to-drastically-improve-your-app-with-an-afternoon-and-instruments&quot;&gt;improved the performance of his date parsing code by a factor of more than 20×&lt;/a&gt; by switching from &lt;code&gt;NSDateFormatter&lt;/code&gt; to C-based date parsing.&lt;/p&gt;

&lt;h2&gt;GMT != UTC&lt;/h2&gt;

&lt;p&gt;Cédric Luthi discovered a &lt;a href=&quot;http://twitter.com/0xced/status/137927496631988224&quot;&gt;seemingly weird &lt;code&gt;NSDateFormatter&lt;/code&gt; behavior&lt;/a&gt; last weekend. See the following code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;NSString &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateString &lt;span class=&quot;hl opt&quot;&gt;=&lt;/span&gt; @&lt;span class=&quot;hl str&quot;&gt;&quot;0001-01-01 00:00:00 GMT&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;;&lt;/span&gt;
NSDateFormatter &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;df &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSDateFormatter alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;df setLocale&lt;span class=&quot;hl opt&quot;&gt;:[[&lt;/span&gt;NSLocale alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithLocaleIdentifier&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;en_US_POSIX&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;]];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;df setDateFormat&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;yyyy-MM-dd HH:mm:ss zzz&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;myDate &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;df dateFromString&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt; dateString&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl kwd&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;%@&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; myDate&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The result of the log statement: &lt;code&gt;0001-01-01 01:27:24 +0000&lt;/code&gt;. Hm, 01:27:24? Where can such a weird result come from? It turns out the answer is the GMT time zone. Do the same with UTC as the time zone and the result is the expected &lt;code&gt;0001-01-01 00:00:00 +0000&lt;/code&gt;. &lt;span class=&quot;update&quot;&gt;&lt;strong&gt;Update November 23, 2011:&lt;/strong&gt; &lt;a href=&quot;https://twitter.com/0xced/status/139289644129984512&quot;&gt;Cédric notes on Twitter&lt;/a&gt; that Snow Leopard doesn’t seem to understand “UTC” and &lt;code&gt;@&quot;0001-01-01 00:00:00 UTC&quot;&lt;/code&gt; returns a &lt;code&gt;nil&lt;/code&gt; date. I find that very strange.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;So it seems that when dealing with historical dates, UTC and GMT are not identical in Cocoa. Instead, the system seems to use past definitions of GMT that were valid at the date in question. When I investigated this further, I found out that only for dates later than 9 April, 1968, GMT and UTC are identical in Cocoa. So beware of the difference if your app deals with the past. Use UTC as your time zone if you want to interpret all dates in today’s time system.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;Wouldn’t it be great if all web services used &lt;a href=&quot;http://en.wikipedia.org/wiki/Unix_timestamp&quot;&gt;Unix timestamps&lt;/a&gt; to represent dates? I could omit this entire section as the conversion from and to &lt;code&gt;NSDate&lt;/code&gt; would be trivial. For some reason, however, most APIs use string-based dates, which at least have the advantage of being human-readable.&lt;a href=&quot;#fnref:1&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;For example, the year-of-week for 1 January 2005 is 2004 because that date belongs to the last calendar week of 2004 rather than the first calendar week of 2005. Use &lt;code&gt;NSDate *testDate = [NSDate dateWithTimeIntervalSinceReferenceDate:126273600.0]&lt;/code&gt; in your unit test and assert that you get the correct result for both format strings &lt;code&gt;@&quot;yyyy&quot;&lt;/code&gt; and &lt;code&gt;@&quot;yyyy&quot;&lt;/code&gt;.&lt;a href=&quot;#fnref:2&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot;&gt;
      &lt;p&gt;By the way, &lt;a href=&quot;http://krillapps.com/coderunner/&quot;&gt;CodeRunner&lt;/a&gt;, which I &lt;a href=&quot;/blog/2011/10/coderunner/&quot;&gt;reviewed recently here on the blog&lt;/a&gt; is an awesome little app to experiment with date formatters. I used it constantly while writing this article.&lt;a href=&quot;#fnref:3&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot;&gt;
      &lt;p&gt;There are a number of apps that let you do just that, for example iCal in Lion, the great &lt;a href=&quot;http://flexibits.com/fantastical&quot;&gt;Fantastical app&lt;/a&gt; and Google Calendar.&lt;a href=&quot;#fnref:4&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot;&gt;
      &lt;p&gt;My time zone is one hour earlier than UTC, hence the time difference between input and output string.&lt;a href=&quot;#fnref:5&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
    </content>
  </entry>
  <entry>
    <id>http://oleb.net/blog/2011/11/working-with-date-and-time-in-cocoa-part-1/</id>
    <title>Working with Date and Time in Cocoa (Part 1)</title>
    <published>2011-11-17T22:55:00Z</published>
    <updated>2011-11-28T19:15:00Z</updated>
    <author>
      <name>Ole Begemann</name>
    </author>
    <link href='http://oleb.net/blog/2011/11/working-with-date-and-time-in-cocoa-part-1/' />
    <link rel="alternate" type="text/html" href='http://oleb.net/blog/2011/11/working-with-date-and-time-in-cocoa-part-1/' />
    <content xml:base="http://oleb.net" type="html">
      &lt;p&gt;One of the most common problems I see newbies to Objective-C and Cocoa struggle with on &lt;a href=&quot;http://stackoverflow.com&quot;&gt;Stack Overflow&lt;/a&gt; is how to deal correctly with dates and times. Cocoa’s approach to date and time handling may indeed seem overly complex at first glance: where other languages’ standard libraries seem to get by with just one or two classes to cover this field, the Foundation framework employs a staggering array of separate classes: &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003641&quot;&gt;&lt;code&gt;NSDate&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDateComponents_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003642&quot;&gt;&lt;code&gt;NSDateComponents&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003643&quot;&gt;&lt;code&gt;NSDateFormatter&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSCalendar_Class/Reference/NSCalendar.html#//apple_ref/doc/uid/TP40003626&quot;&gt;&lt;code&gt;NSCalendar&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSTimeZone_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003748&quot;&gt;&lt;code&gt;NSTimeZone&lt;/code&gt;&lt;/a&gt;. These classes deal directly with date and time and you should be familiar with all of them. In addition, you should also understand the role of the &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSLocale_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003674&quot;&gt;&lt;code&gt;NSLocale&lt;/code&gt;&lt;/a&gt; class.&lt;/p&gt;

&lt;p&gt;Let’s have a look at those classes one by one. As you will see, the Cocoa approach to date and time handling is not only quite easy to understand but also extremely flexible.&lt;/p&gt;

&lt;h1&gt;NSDate&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;NSDate&lt;/code&gt; is the central class of the date/time handling in Foundation, and at the same time the simplest imaginable. &lt;code&gt;NSDate&lt;/code&gt; is nothing more than a wrapper around a single number: the number of seconds since 1 January, 2001, at 00:00 (midnight), &lt;a href=&quot;http://en.wikipedia.org/wiki/Coordinated_Universal_Time&quot;&gt;UTC&lt;/a&gt;&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. For values representing numbers of seconds, the framework uses a custom type, &lt;code&gt;NSTimeInterval&lt;/code&gt;, which is currently defined as a 64-bit floating point value. According to the documentation, this is enough to yield an impressive &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_DataTypes/Reference/reference.html#//apple_ref/doc/uid/20000018-SW69&quot;&gt;&lt;q&gt;sub-millisecond precision over a range of 10,000 years&lt;/q&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Represents an Absolute Point in Time&lt;/h2&gt;

&lt;p&gt;An &lt;code&gt;NSDate&lt;/code&gt; object always represents an absolute point in time.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a href=&quot;#fn:2&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; This insight has two important consequences:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
    &lt;p&gt;&lt;em&gt;There is no way to represent a certain date without including a specific time.&lt;/em&gt; For instance, to say that a particular &lt;code&gt;NSDate&lt;/code&gt; instance represents &lt;em&gt;17 November 2011&lt;/em&gt; makes no sense; you always have to include the particular time and time zone, such as &lt;em&gt;17 November 2011 00:00:00 +00:00&lt;/em&gt; (or any other time of your choice).&lt;/p&gt;

    &lt;p&gt;If your app needs to store dates with less-than-second precision in order to represent entire days, months or years, you should either not use your own custom class for this or, better, define a rule how your app deals with the &lt;em&gt;unused&lt;/em&gt; components of the date (e.g., set the time components of the date to &lt;em&gt;00:00:00 +00:00&lt;/em&gt;).&lt;/p&gt;

    &lt;p&gt;If you are sloppy and store dates with arbitrary time components, you will run into problems later when you want to compare or group multiple dates.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;&lt;code&gt;NSDate&lt;/code&gt; has no concept of time zones.&lt;/em&gt; When it is midnight in London (&lt;em&gt;17 November 2011 00:00:00 +00:00&lt;/em&gt;), it is only 6 pm on the day before in New York (&lt;em&gt;16 November 2011 18:00:00 -06:00&lt;/em&gt;). Both dates represent the &lt;em&gt;same point in time&lt;/em&gt; and are thus &lt;em&gt;absolutely equal&lt;/em&gt; as far as &lt;code&gt;NSDate&lt;/code&gt; is concerned.&lt;/p&gt;

    &lt;p&gt;The implication of this is that you cannot store the time zone of a date and time in an &lt;code&gt;NSDate&lt;/code&gt; object. If your app needs this information, you will have to store it in a different field. But more often than not, you will find that the time zone is actually not a field that should be stored with a date. Rather, it is a &lt;em&gt;runtime&lt;/em&gt; preference of the person that is currently using your app, and your app should probably display most dates in the user’s current time zone.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;&lt;h2&gt;How To Create An &lt;code&gt;NSDate&lt;/code&gt; That Represents A Specific Date?&lt;/h2&gt;

&lt;p&gt;The easiest way to create an &lt;code&gt;NSDate&lt;/code&gt; object is &lt;code&gt;[NSDate date];&lt;/code&gt;. This will return an instance that represents the current moment and is often useful in code when it comes to storing creation or modification dates of records or to measure certain time intervals in your app.&lt;/p&gt;

&lt;p&gt;The more generic task of creating an instance that represents a specific date and time turns out to be not so straightforward. There is the &lt;code&gt;+dateWithTimeIntervalSinceReferenceDate:&lt;/code&gt; class method, but it requires you to know the interval in seconds between your desired date and the reference date (1 January 2001 00:00:00 +00:00). Turns out most people don’t count dates that way. That’s where the other classes come in.&lt;/p&gt;

&lt;h1&gt;NSCalendar&lt;/h1&gt;

&lt;p&gt;Most people reading this will probably only ever use the same single calendar with its 12 months named January, February and so on, seven-day weeks, counting the years from the reputed birth of Jesus. It is easy to forget that (1) the current “western” &lt;a href=&quot;http://en.wikipedia.org/wiki/Gregorian_calendar&quot;&gt;Gregorian Calendar&lt;/a&gt; has only been introduced in 1582 and (2) there are many more calendars in practical use around the world today. The Foundation framework can currently handle &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSLocale_Class/Reference/Reference.html#//apple_ref/doc/uid/TP30001224-SW41&quot;&gt;ten different calendars&lt;/a&gt;&lt;sup id=&quot;fnref:3&quot;&gt;&lt;a href=&quot;#fn:3&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;It should be clear that, to specify a date unambiguously, we need to specify the calendar we use. For instance, while today’s date falls into the year 2011 in the familiar Gregorian calendar, the current year is 2554 and 5772 in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Buddhist_calendar&quot;&gt;Buddhist&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Hebrew_calendar&quot;&gt;Hebrew&lt;/a&gt; calendars, respectively.&lt;/p&gt;

&lt;p&gt;In Cocoa, a calendar is represented by the &lt;code&gt;NSCalendar&lt;/code&gt; class. To create an instance of a specific calendar, pass one of the valid &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSLocale_Class/Reference/Reference.html#//apple_ref/doc/uid/TP30001224-SW41&quot;&gt;calendar identifiers&lt;/a&gt; to the initializer:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;NSCalendar &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;gregorian &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSCalendar alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithCalendarIdentifier&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSGregorianCalendar&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSCalendar &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;buddhist &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSCalendar alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithCalendarIdentifier&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSBuddhistCalendar&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSCalendar &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;hebrew &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSCalendar alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithCalendarIdentifier&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSHebrewCalendar&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are also two class methods, &lt;code&gt;+currentCalendar&lt;/code&gt; and &lt;code&gt;+autoupdatingCurrentCalendar&lt;/code&gt; that return the current user’s preferred calendar. Note that the object returned by the latter method automatically adapts to changes in System Preferences.&lt;/p&gt;

&lt;p&gt;The rest of the class is pretty straightforward. You can query the calendar for its configuration, i.e., things like the number of days that are in a month or which day is considered the first day of the week. Have a look at the &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSCalendar_Class/Reference/NSCalendar.html#//apple_ref/doc/uid/TP40003626&quot;&gt;documentation&lt;/a&gt; to get a feel for what is possible. There are also methods to split a date into its calendrical components or do the reverse but we are not quite ready to do that yet.&lt;/p&gt;

&lt;h1&gt;NSTimeZone&lt;/h1&gt;

&lt;p&gt;Any time specification is not precise enough without also indicating the time zone. I have already discussed that we need a way to reference time zones separately from &lt;code&gt;NSDate&lt;/code&gt; and the &lt;code&gt;NSTimeZone&lt;/code&gt; class does just that. There are several methods to create a time zone instance, the most straightforward being &lt;code&gt;+timeZoneForSecondsFromGMT:&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note, though, that the numeric offset from GMT is in many cases not enough to identify a specific time zone due to different daylight saving rules around the world. It is safer to specify a time zone by name using the &lt;code&gt;+timeZoneWithName:&lt;/code&gt; method. Valid names are of the form &lt;code&gt;@&quot;Europe/Berlin&quot;&lt;/code&gt;.&lt;sup id=&quot;fnref:4&quot;&gt;&lt;a href=&quot;#fn:4&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Another method, &lt;code&gt;+timeZoneWithAbbreviation:&lt;/code&gt; should be handled with care. It is supposed to create time zones from common abbreviations such as “PST” or “CEST”. The problem is that these abbreviations are not always unique – different countries might use the same abbreviation for different time zones or different abbreviations for the same time zone. You should avoid this ambiguity if possible.&lt;/p&gt;

&lt;p class=&quot;update&quot;&gt;&lt;strong&gt;Update November 22, 2011:&lt;/strong&gt; In addition, the rules which time zone abbreviation is understood under a specific locale setting can change. As Cédric Luthi found out, &lt;a href=&quot;http://www.openradar.me/9944011&quot;&gt;Apple made a change in iOS 5&lt;/a&gt; that causes the abbreviations “CET” and “CEST” (Central European (Summer) Time, very commonly used in Europe) to be no longer recognized if the user’s current locale setting is &lt;em&gt;en_US&lt;/em&gt;. These abbreviations do still work with the &lt;em&gt;en_GB&lt;/em&gt; locale, however. Another reason to avoid them completely if you ask me.&lt;/p&gt;

&lt;p&gt;Last but not least, use the &lt;code&gt;+systemTimeZone&lt;/code&gt; method to get a reference to the user’s current time zone.&lt;/p&gt;

&lt;h1&gt;NSDateComponents&lt;/h1&gt;

&lt;p&gt;We have almost everything we need now to manipulate dates in our code. Our fourth class, &lt;code&gt;NSDateComponents&lt;/code&gt;, represents kind of the same information as &lt;code&gt;NSDate&lt;/code&gt;: a single point in time. Unlike the latter, however, an &lt;code&gt;NSDateComponents&lt;/code&gt; instance lets you access and manipulate every single calendrical component of that absolute point&lt;sup id=&quot;fnref:5&quot;&gt;&lt;a href=&quot;#fn:5&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;, from the year down to the second and including such things as era, calendar, time zone and weekday.&lt;/p&gt;

&lt;h2&gt;Constructing Dates&lt;/h2&gt;

&lt;p&gt;Knowing this, let’s construct a date that represents the beginning of Steve Jobs’s Macworld 2007 keynote when he first introduced the iPhone:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;NSCalendar &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;gregorian &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSCalendar alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; initWithCalendarIdentifier&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSGregorianCalendar&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSTimeZone &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;pacificTime &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSTimeZone timeZoneWithName&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;America/Los_Angeles&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;

NSDateComponents &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateComps &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSDateComponents alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateComps setCalendar&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;gregorian&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateComps setYear&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;2007&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateComps setMonth&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateComps setDay&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateComps setTimeZone&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;pacificTime&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateComps setHour&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;hl slc&quot;&gt;// keynote started at 9:00 am&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateComps setMinute&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;hl slc&quot;&gt;// default value, can be omitted&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;dateComps setSecond&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;hl slc&quot;&gt;// default value, can be omitted&lt;/span&gt;

NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateOfKeynote &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;dateComps date&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl kwd&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;Date of Keynote: %@&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; dateOfKeynote&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
Date of Keynote: 2007-01-09 17:00:00 +0000
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Hm, 17:00:00? But remember that &lt;code&gt;NSDate&lt;/code&gt; does not care about time zones. When printing an &lt;code&gt;NSDate&lt;/code&gt; with &lt;code&gt;NSLog()&lt;/code&gt;, the system always uses UTC, which is 8 hours ahead of San Francisco (or 7 hours during daylight savings time). So the resulting date is indeed correct.&lt;/p&gt;

&lt;div class=&quot;update&quot;&gt;
  &lt;p&gt;&lt;strong&gt;Update November 28, 2011:&lt;/strong&gt; Thanks to Shan for &lt;a href=&quot;http://twitter.com/lakesidelatte/status/139682491207389184&quot;&gt;pointing out on Twitter&lt;/a&gt; that the code snippet above won’t work on OS X 10.6 or iOS 3.x because the &lt;code&gt;setCalendar:&lt;/code&gt; and &lt;code&gt;setTimeZone:&lt;/code&gt; methods are quite recent additions to &lt;code&gt;NSDateComponents&lt;/code&gt;. To stay compatible with the older OSs, create your &lt;code&gt;NSDateComponents&lt;/code&gt; instance just as above (without setting a calendar and time zone) and use the &lt;code&gt;dateFromComponents:&lt;/code&gt; method of &lt;code&gt;NSCalendar&lt;/code&gt;:&lt;/p&gt;

  &lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;...
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;gregorian setTimeZone&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;pacificTime&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateOfKeynote &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;gregorian dateFromComponents&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;dateComps&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl kwd&quot;&gt;NSLog&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;(&lt;/span&gt;@&lt;span class=&quot;hl str&quot;&gt;&quot;Date of Keynote: %@&quot;&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;,&lt;/span&gt; dateOfKeynote&lt;span class=&quot;hl opt&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

  &lt;p&gt;You see, it’s just as easy.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Now that we have an &lt;code&gt;NSDateComponents&lt;/code&gt; instance, you would perhaps expect that you can get more information out of it. For example, let’s try to find out what day of the week the keynote was:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;NSInteger weekday &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;dateComps weekday&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;hl slc&quot;&gt;// =&amp;gt; -1 == NSUndefinedDateComponent&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The documentation explains this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;An instance of &lt;code&gt;NSDateComponents&lt;/code&gt; is not responsible for answering questions about a date beyond the information with which it was initialized. For example, if you initialize one with May 6, 2004, its weekday is &lt;code&gt;NSUndefinedDateComponent&lt;/code&gt;, not Thursday. To get the correct day of the week, you must create a suitable instance of &lt;code&gt;NSCalendar&lt;/code&gt;, create an &lt;code&gt;NSDate&lt;/code&gt; object using &lt;code&gt;dateFromComponents:&lt;/code&gt; and then use &lt;code&gt;components:fromDate:&lt;/code&gt; to retrieve the weekday.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s try that:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;dateOfKeynote &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;dateComps date&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;hl slc&quot;&gt;// or: [gregorian dateFromComponents:dateComps]&lt;/span&gt;
NSDateComponents &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;weekdayComponents &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;gregorian components&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;NSWeekdayCalendarUnit fromDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;dateOfKeynote&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSInteger weekday &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;weekdayComponents weekday&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;hl slc&quot;&gt;// =&amp;gt; 3 == Tuesday&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note how we can specify in the &lt;code&gt;-[NSCalendar components:fromDate:]&lt;/code&gt; method which date components we are interested in (using a bit mask). Some of the components can be expensive so it makes sense to only ask for the information you really need.&lt;/p&gt;

&lt;h2&gt;Date Calculations&lt;/h2&gt;

&lt;p&gt;The combination of &lt;code&gt;NSDateComponents&lt;/code&gt; and &lt;code&gt;NSCalendar&lt;/code&gt; is also the way to go for fancy date calculations. Say I want to create a date that goes back in time by exactly a month, a day and an hour from the current moment (using the current user’s calendar):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objc&quot;&gt;NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;now &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSDate date&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSDateComponents &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;comps &lt;span class=&quot;hl opt&quot;&gt;= [[&lt;/span&gt;NSDateComponents alloc&lt;span class=&quot;hl opt&quot;&gt;]&lt;/span&gt; init&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;comps setMonth&lt;span class=&quot;hl opt&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;comps setDay&lt;span class=&quot;hl opt&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;hl opt&quot;&gt;[&lt;/span&gt;comps setHour&lt;span class=&quot;hl opt&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSCalendar &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;calendar &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;NSCalendar currentCalendar&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;
NSDate &lt;span class=&quot;hl opt&quot;&gt;*&lt;/span&gt;newDate &lt;span class=&quot;hl opt&quot;&gt;= [&lt;/span&gt;calendar dateByAddingComponents&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;comps toDate&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;now options&lt;span class=&quot;hl opt&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl num&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hl opt&quot;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;NSDateComponents&lt;/code&gt; is an incredibly flexible und useful class. In combination with &lt;code&gt;NSCalendar&lt;/code&gt;, you can probably do all the date calculations you ever thought of.&lt;/p&gt;

&lt;h1&gt;Continued in Part 2: Date Parsing and Formatting&lt;/h1&gt;

&lt;p&gt;The classes I presented above give you a complete toolkit to work with date and time in your code. Two things are still missing, though: how to parse dates that come into your app as strings and how to output properly formatted dates as strings? Both of these tasks are handled by the &lt;code&gt;NSDateFormatter&lt;/code&gt; class, which &lt;a href=&quot;/blog/2011/11/working-with-date-and-time-in-cocoa-part-2/&quot;&gt;I discuss in part 2 of this little series&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;Or &lt;a href=&quot;http://en.wikipedia.org/wiki/Greenwich_Mean_Time&quot;&gt;GMT&lt;/a&gt;, which is arguably the same, at least for our purposes.&lt;a href=&quot;#fnref:1&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot;&gt;
      &lt;p&gt;Yes, that means the date and time system does not deal with &lt;a href=&quot;http://en.wikipedia.org/wiki/Special_relativity&quot;&gt;relativity&lt;/a&gt;. Cocoa is deeply rooted in &lt;a href=&quot;http://en.wikipedia.org/wiki/Absolute_time_and_space&quot;&gt;Newtonian physics&lt;/a&gt;. &lt;span class=&quot;update&quot;&gt;&lt;strong&gt;Update November 23, 2011:&lt;/strong&gt; We also pretend that &lt;a href=&quot;http://en.wikipedia.org/wiki/Leap_second&quot;&gt;leap seconds&lt;/a&gt; do not exist.&lt;/span&gt;&lt;a href=&quot;#fnref:2&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot;&gt;
      &lt;p&gt;With some limitations regarding the Chinese calendars. See the description of &lt;a href=&quot;http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSLocale_Class/Reference/Reference.html#//apple_ref/doc/uid/TP30001224-SW41&quot;&gt;valid calendar identifiers in the documentation&lt;/a&gt;.&lt;a href=&quot;#fnref:3&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot;&gt;
      &lt;p&gt;Apple uses the well-known &lt;a href=&quot;http://en.wikipedia.org/wiki/Tz_database&quot;&gt;tz database&lt;/a&gt;. Log the result of &lt;code&gt;+knownTimeZoneNames&lt;/code&gt; to get a list of all valid names.&lt;a href=&quot;#fnref:4&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot;&gt;
      &lt;p&gt;Implied in this is that &lt;code&gt;NSDateComponents&lt;/code&gt; objects are mutable whereas &lt;code&gt;NSDate&lt;/code&gt; instances are immutable.&lt;a href=&quot;#fnref:5&quot; rel=&quot;reference&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
    </content>
  </entry>
</feed>
