<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Use Your Loaf</title>
    <link>http://useyourloaf.com</link>
    <atom:link href="http://useyourloaf.com/blog/rss.xml" rel="self" type="application/rss+xml"/>
    <description>Developing for the Apple iPhone and iOS.</description>
    <copyright>Copyright 2013 Keith Harrison</copyright>
    <language>en-GB</language>
    <lastBuildDate>Wed, 22 May 2013 13:29:45 +0100</lastBuildDate>
    <generator>Octopress</generator>
    
    <item>
		  <title>State Preservation and Restoration</title>
		  <link>http://useyourloaf.com/blog/2013/05/21/state-preservation-and-restoration.html</link>
      <pubDate>Tue, 21 May 2013 12:00:00 +0100</pubDate>
		  <guid>http://useyourloaf.com/blog/2013/05/21/state-preservation-and-restoration.html</guid>
      
        <category>State Restoration</category>
      
        <category>iOS 6</category>
      
      <description><![CDATA[<p>From the very first releases of the iPhone SDK Apple has encouraged developers to think about app startup and switching to make the experience as quick and transparent as possible for the user. The limited resources of mobile devices mean that App termination is a common occurrence. Returning to a previously running App that has been terminated by the system and finding it back at a startup screen is not a great user experience. The ability for an App to be suspended and resumed was introduced with iOS 4 and helps to reduce the problem but to make App termination transparent to the end user still takes developer effort.</p>

<p>There is a non-trivial amount of work required to save and then restore a deeply nested hierarchy of views and view controllers. Luckily with iOS 6 direct UIKit support for state preservation and restoration was introduced. This post is a collection of my notes on the basic steps to implement state preservation and restoration.</p>

<h3>State Restoration Flowchart</h3>

<p>A key point to understand about the way UIKit implements state preservation is that it happens when the App moves to the background. You indicate to UIKit which view controllers and views you want to preserve by assigning them restoration identifiers and UIKit then does the hard work of saving the necessary data to an archive file. If the App is then terminated by the system whilst it is suspended the saved archive can be used to restore the App state the next time it is launched.</p>

<p>The state restoration process is controlled by a series of interactions between UIKit, the Application Delegate and the preserved view controllers and views as summarised in the following flowchart:</p>

<p><img src="http://useyourloaf.com/assets/images/2013/StateRestoration.png" alt="State Restoration" /></p>

<h3>A Simple Example</h3>

<p>As always it is easier to show the key concepts by way of example so here is a
very simple example application with only a few UI elements. The main user interface is a tab-bar controller with two tab-bar items. The first tab is a table view controller embedded in a navigation controller. The table view shows a list of countries, selecting a row navigates to a detailed view controller showing details about the country. The second tab is a settings view containing a single UISwitch.</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-05-19-001.png" alt="" />
<img src="http://useyourloaf.com/assets/images/2013/2013-05-19-002.png" alt="" /></p>

<p>The following application state should be restored when the App is launched:</p>

<ul>
<li>The selected tab in the tab-bar should be restored.</li>
<li>Scroll position and any selection of the table view should be restored</li>
<li>Navigation hierarchy of the Navigation Controller (the table view or detailed view may be visible).</li>
</ul>


<p>This is a good point to differentiate between an applications data model and user interface state. The state preservation and restoration system is intended to take care of the user interface state. As we will see shortly the state preservation data will be deleted if the user force-quits the App or if the restoration process fails. You should therefore NOT attempt to use it to store the applications data model. The data model is best stored to a persistent data store for example by writing it to a file, database or something like Core Data. When a view is restored it can of course make use of the persistent data model to correctly configure the restored view.</p>

<p>In this simple example the table view data source is loaded from a plist file and the current state of the settings are saved to the user defaults (using NSUserDefaults). The state of the switch is initialised when the settings view is loaded and saved any time it changes:</p>

<pre><code>- (void)viewDidLoad
{
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  self.amazingSwitch.on = [defaults boolForKey:kUYLSettingsAmazingKey];
}

- (IBAction)amazingAction
{
  BOOL amazingEnabled = self.amazingSwitch.isOn;
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  [defaults setBool:amazingEnabled forKey:kUYLSettingsAmazingKey];
  [defaults synchronize];
}
</code></pre>

<h3>Changes To The Application Delegate Launch Process</h3>

<p>If you refer back to the earlier flowchart you will see that with iOS 6 there are now two methods available in the application delegate to initialise the App post launch:</p>

<ul>
<li>application:willFinishLaunchingWithOptions:</li>
<li>application:didFinishLaunchingWithOptions:</li>
</ul>


<p>The major difference between these two methods is that the &#8220;willFinish&#8221; method, which is new in iOS 6, is called before state restoration is performed. The &#8220;didFinish&#8221; method is called after any state restoration has occurred. As a general guideline you will want to perform most application initialisation before state restoration takes place so that things such as the data model are available when the view controllers are restored.</p>

<p>If you have an existing App that has initialisation code in application:didFinishLaunchingWithOptions: you can mostly just move this code to the new application:willFinishLaunchingWithOptions: method. However you need to be careful if you want backward compatibility to iOS 5 or earlier versions as the &#8220;willFinish&#8221; method will never be invoked. One approach is to move everything to a common initialisation method and invoke it from both methods. You can further wrap the initialisation code in a dispatch_once block if you need to ensure the initialisation is executed only once:</p>

<pre><code>- (void)commonFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  static dispatch_once_t onceToken;
  dispatch_once(&amp;onceToken, ^{
    NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
                                 [NSNumber numberWithBool:YES], kUYLSettingsAmazingKey,
                                 nil];
    [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
  });
}

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  [self commonFinishLaunchingWithOptions:launchOptions];
  return YES;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  [self commonFinishLaunchingWithOptions:launchOptions];
  return YES;
}
</code></pre>

<p>If you do not care about backward compatibility with iOS 5 you can avoid this extra work and directly place your initialisation code in the appropriate app delegate method.</p>

<h3>Basic Steps to Enable State Preservation</h3>

<p>To get started with state preservation and restoration there are two basic steps that are always required:</p>

<ul>
<li>The App delegate must opt-in</li>
<li>Each view controller or view to be preserved/restored must have a restoration identifier assigned.</li>
</ul>


<p>In addition to these mandatory steps there are also a number of optional but very common steps:</p>

<ul>
<li>Create restoration classes for any view controllers that need to be recreated during a restore that are not otherwise created on App launch.</li>
<li>Implement encodeRestorableStateWithCoder: and decodeRestorableStateWithCoder: for views and view controllers that require state to be saved and restored.</li>
<li>Implement the UIDataSourceModelAssociation protocol for objects that are data sources for table and collection views to save and restore which rows are visible and which are selected.</li>
</ul>


<h3>Application Delegate Opt-in</h3>

<p>State preservation and restoration is an optional feature so you need
to have the application delegate opt-in by implementing two methods:</p>

<pre><code>- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder
{
  return YES;
}

- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder
{
  return YES;
}
</code></pre>

<p>Most of the time you just want to return YES to indicate support for state preservation and restoration. However if you release an App upgrade where it would not make sense to restore from a previous version you can return NO from application:shouldRestoreApplicationState:. This might be the case if you have completely changed the view hierarchy for example.</p>

<h3>Restoration Identifier</h3>

<p>A restoration identifier is a string that you need to assign to any view controller or view that you want preserved and restored. During state preservation any view controllers or views in the view hierarchy that have a restoration identifier will be saved to disk.</p>

<p>The restorationIdentifier property can be set when the view controller is initialised but if you are loading the view controller from a Nib or Storyboard you can also set it there. You can choose any value you want as the identifier but you must ensure that the restoration path (the sequence of restoration identifiers down the view hierarchy from the root view controller) is unique for each object to be restored.</p>

<p>For our simple example project we can set the restoration identifiers in the Storyboard. For view controllers you can use Interface Builder to set a Storyboard ID and by selecting the option reuse the same ID for the Restoration ID:</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-05-20-001.png" alt="" /></p>

<p>Restoration identifiers need to be set for the following view controllers:</p>

<ul>
<li>The Tab Bar Controller</li>
<li>Both Navigation Controllers</li>
<li>The Table View Controller and the associated UITableView</li>
<li>The Settings View Controller</li>
</ul>


<p>An easy mistake to make when using Interface Builder is to set the restoration identifier on the wrong object. For example, be sure to set the restoration identifier on the table view itself and not on the table view cell. The following screenshot of the storyboard shows the identifiers I used for each of the view controllers:</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-05-20-002.png" alt="" /></p>

<h3>Finding or Creating View Controllers During Restoration</h3>

<p>During the restoration process UIKit will attempt to create or locate a reference to each view controller that is being restored. If the main user interface is loaded from a Nib file or Storyboard then it will already have been created when the application launched. In that case UIKit will locate the already created view controller instead of creating a new instance.</p>

<p>In this simple example all of the view controllers to be restored are located in the Storyboard file that is loaded when the application launches. This means we have nothing else to do as UIKit will take care of recreating the view controllers for us (we still need to restore the state of the view controllers). For view controllers that are not created as part of the normal application launch UIKit attempts the following steps:</p>

<ul>
<li>If the view controller has a restoration class (it implements the UIViewControllerRestoration protocol) then UIKit will use it to call the viewControllerWithRestorationIdentiferPath:coder: method. By implementing that method you can return an instance of the view controller.</li>
<li>If the view controller does not have a restoration class UIKit will call application:viewControllerWithRestorationIdentifierPath:coder: in the application delegate.</li>
</ul>


<p>I will save a detailed discussion of using a restoration class in a future post.</p>

<h3>Restoring State of View Controllers and their Views</h3>

<p>Once all of the view controllers we need have been created we need to restore any state they may need to properly recreate the user interface and any associated subviews they may contain. For any object where we have set a restoration identifier we have the option to save and restore state information by implementing the following two methods:</p>

<ul>
<li>encodeRestorableStateWithCoder:</li>
<li>decodeRestorableStateWithCoder:</li>
</ul>


<p>In our example App we have a view controller (UYLCountryViewController) that is used to display a view with the name of the capital city of the country selected in the root table view controller. The data model for this view controller is just an NSString property which is set when the view controller is pushed onto the navigation stack:</p>

<pre><code>@property (nonatomic, copy) NSString *capital;
</code></pre>

<p>When this view controller is restored we need to ensure that we also restore this data. In this case the encode and decode methods that we need to implement are as follows:</p>

<pre><code>- (void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
  [coder encodeObject:self.capital forKey:UYLKeyCapital];
  [super encodeRestorableStateWithCoder:coder];
}

- (void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
  self.capital = [coder decodeObjectForKey:UYLKeyCapital];
  [super decodeRestorableStateWithCoder:coder];
}
</code></pre>

<p>Note that in both cases you need to call super to ensure the parent view controller gets a chance to save and restore state.</p>

<h3>Preserving Table View State</h3>

<p>For the table view showing the list of countries we want to be able save the current selection and the scroll position. Since the data source can change between launches of an application this is a little more complicated than just saving the indexPath of the selected and first visible row. Relying on the indexPath will give us wrong results if when we restore a number of rows have been deleted or added to the table.</p>

<p>What we need to do is map between the indexPath and an identifier we can use to uniquely locate data items. To do that we need to adopt the UIDataSourceModelAssociation protocol:</p>

<pre><code>@interface UYLTableViewController () &lt;UIDataSourceModelAssociation&gt;
</code></pre>

<p>This protocol has two required methods to map between an index path of an object in the table and an NSString identifier:</p>

<ul>
<li>modelIdentifierForElementAtIndexPath:inView:</li>
<li>indexPathForElementWithModelIdentifier:inView:</li>
</ul>


<p>In this simple example we can use the country name to uniquely identify an object in the table. For a Core Data backed data model a good choice would be a string representation of the managed object ID. The method used when saving the state which maps an index path to a string identifier is straightforward:</p>

<pre><code>- (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inView:(UIView *)view
{
  NSString *identifier = nil;
  if (indexPath &amp;&amp; view)
  {
    NSDictionary *country = [self.worldData objectAtIndex:indexPath.row];
    identifier = [country valueForKey:@"capital"];
  }
  return identifier;
}
</code></pre>

<p>The method used on restoration needs to map back to an index path for the object based on the identifier. This is a little more complicated in this case as we need to search an array of dictionaries for the matching object. Luckily we have a way to <a href="http://useyourloaf.com/blog/2010/10/19/searching-arrays-with-nspredicate-and-blocks.html">search an array using an NSPredicate and a block</a>:</p>

<pre><code>- (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view
{
  NSIndexPath *indexPath = nil;
  if (identifier &amp;&amp; view)
  {
    NSPredicate *capitalPred = [NSPredicate predicateWithFormat:@"capital == %@", identifier];
    NSInteger row = [self.worldData indexOfObjectPassingTest:
                     ^(id obj, NSUInteger idx, BOOL *stop)
                     {
                       return [capitalPred evaluateWithObject:obj];
                     }];

    if (row != NSNotFound)
    {
      indexPath = [NSIndexPath indexPathForRow:row inSection:0];
    }
  }

  // Force a reload when table view is embedded in nav controller
  // or scroll position is not restored. Uncomment following line
  // to workaround bug.
  [self.tableView reloadData];

  return indexPath;
}
</code></pre>

<p>Note that in the case that we cannot find the object because it has been deleted from the dataset we return nil. Also note that because of a bug in iOS 6 we need to force a reload of the table view or the scroll position is not restored. See this previous post about the <a href="http://useyourloaf.com/blog/2013/04/07/bug-table-view-state-not-restored-when-embedded-in-navigation-controller.html">table view state not being restored when embedded in a navigation controller</a> or also see <a href="https://openradar.appspot.com/13438788">rdar://13438788</a> for more details.</p>

<h3>Testing</h3>

<p>At this point we have done everything we need to save and restore state for this simple App. We can test the results using either the simulator or a device but you need to remember a key point I mentioned earlier. The state is only saved when the App is moved to the background and will be deleted if you force quit the App. The easiest way to test state restoration using the simulator is with the following procedure:</p>

<ul>
<li>Launch the App in the simulator and navigate to create the required App state.</li>
<li>Use the home button (⇧⌘H) to send the App to the background.</li>
<li>Stop the App using Xcode.</li>
</ul>


<p>At this point we have an App that is not running but has some saved background state. To test that the state is restored you can relaunch the App directly in the Simulator or by running it again from Xcode. A common mistake I find myself making when testing is to stop the App before sending it to the background.</p>

<h3>Wrapping Up</h3>

<p>This has been a long post considering that I only covered the basics but hopefully you have managed to follow along. I do think that for many simple use cases it is pretty simple to implement as UIKit really does take care of most of the work. I will try to explore some of the more advanced topics such as the use of restoration classes in a future post. In the mean time you can find the example Restorer XCode project in my <a href="https://github.com/kharrison/CodeExamples/tree/master/Restorer">GitHub CodeExamples</a> repository.</p>

        <hr><p><a href="http://useyourloaf.com/blog/2013/05/21/state-preservation-and-restoration.html">State Preservation and Restoration</a> was originally posted 21 May 2013 on <a href="http://useyourloaf.com">http://useyourloaf.com</a>. Copyright 2013 Keith Harrison.</p>]]></description>
    </item>
    
    <item>
		  <title>Bug Table View State Not Restored When Embedded In Navigation Controller</title>
		  <link>http://useyourloaf.com/blog/2013/04/07/bug-table-view-state-not-restored-when-embedded-in-navigation-controller.html</link>
      <pubDate>Sun, 07 Apr 2013 21:42:00 +0100</pubDate>
		  <guid>http://useyourloaf.com/blog/2013/04/07/bug-table-view-state-not-restored-when-embedded-in-navigation-controller.html</guid>
      
        <category>Radar</category>
      
        <category>State Restoration</category>
      
        <category>tableviewcontroller</category>
      
      <description><![CDATA[<p><em>Sharing this bug report (<a href="https://openradar.appspot.com/13438788">rdar://13438788</a> duplicate of #12156999) for anybody attempting to get iOS 6 state preservation and restoration working for a table view embedded in a navigation controller.</em></p>

<h3>Problem Description</h3>

<h4>Summary</h4>

<p>Using iOS 6 state preservation and restoration the first visible row of a UITableView is not restored when the table view is embedded in a UINavigationController.</p>

<h4>Steps to Reproduce</h4>

<p><em>(using Xcode 4.6.1 and iOS 6.1.3)</em></p>

<ol>
<li><p>Create a new Xcode project using the iOS Single View Application template, specifying iPhone, Use Storyboards, Use Automatic Reference Counting.</p></li>
<li><p>Enable state preservation and restoration in the App delegate by implementing application:shouldSaveApplicationState: and application:shouldRestoreApplicationState:. Both methods should return YES.</p></li>
<li><p>Add a new class to the project that is a subclass of UITableViewController (without a XIB). Implement the two mandatory UITableViewDataSource delegate methods to provide a basic data source:</p>

<pre><code> - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 {
   return 1000;
 }

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
   static NSString *CellIdentifier = @"BasicCell";
   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
   cell.textLabel.text = [NSString stringWithFormat:@"Cell #%d",indexPath.row];
   return cell;
 }
</code></pre></li>
<li><p>Replace the storyboard contents with a single Table View Controller. Change the class of the controller to the name of the class created in step 3.</p></li>
<li><p>In the storyboard set the Table View Cell style to Basic and set the cell reuse identifier to &#8220;BasicCell&#8221; as specified in step 3.</p></li>
<li><p>Embed the table view controller in a navigation controller (Editor > Embed In > Navigation Controller).</p></li>
<li><p>Set the Storyboard ID for the navigation controller and the table view controller and select the &#8220;Use Storyboard ID&#8221; option to use the same identifier for the restortation ID. Also set the restoration ID for the table view.</p></li>
<li><p>Build and run</p></li>
<li><p>Scroll down the table view until row 50 is the first visible row. Use the home button to move the App to the background and then use Xcode to stop the App.</p></li>
<li><p>Run the app again to see the restored state.</p></li>
</ol>


<h4>Expected Results</h4>

<p>The first visible row should be row 50 which was the first visible row when the App was terminated.</p>

<h4>Actual Results</h4>

<p>The first visible row is row 0.</p>

<h4>Regression</h4>

<p>Delete the navigation controller from the storyboard and repeat the test. On restoring the app the first visible row is row 50.</p>

<h4>Notes</h4>

<p>A sample Xcode project to reproduce the problem can be found in my <a href="https://github.com/kharrison/CodeExamples/tree/master/BUG%20TableView%20State%20Restore">GitHub Code Examples repository</a>. The project contains two storyboards to demonstrate state restoration of a table
view both when it is the root view and when it is embedded in a navigation
controller:</p>

<ul>
<li><p>If the Target settings are used to set the Main Storyboad to NavStoryboard the
user interface consists of UITableView embedded in a Navigation Controller. In
this use case the table view state is not restored.</p></li>
<li><p>If the Target settings are used to set the Main Storyboard to MainStoryboard the user interface consists of a single UITableView which does have state restored as expected.</p></li>
</ul>


<h3>Workarounds</h3>

<p>Apple engineers suggested the following workaround which I can confirm resolves the issue:</p>

<p><em>Please do the following in the ViewController that owns the TableView:</em></p>

<pre><code>- (void) encodeRestorableStateWithCoder:(NSCoder *)coder {
  // Save anything relevant for our role as the TableView's DataSource
  [super encodeRestorableStateWithCoder:coder];
}

- (void) decodeRestorableStateWithCoder:(NSCoder *)coder {
  [super decodeRestorableStateWithCoder:coder];
  // Restore whatever we need as the TableView's DataSource, and then...
  [self.tableView reloadData];
}
</code></pre>

<p>I have also found that implementing a similar workaround with the UIDataSourceModelAssociation protocol methods works:</p>

<pre><code>- (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)indexPath inView:(UIView *)view
{
  // Determine identifier for the current index path
  NSString *identifier = ....
  return identifier;
}

- (NSIndexPath *)indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view
{
  // Determine index path for the identifier
  NSIndexPath *indexPath = ...

  // Force a reload when table view is embedded in nav controller
  // or scroll position is not restored
  [self.tableView reloadData];

  return indexPath;
}
</code></pre>

<p>The key to both workarounds is to force a reload of the table view data once the state has been restored.</p>

        <hr><p><a href="http://useyourloaf.com/blog/2013/04/07/bug-table-view-state-not-restored-when-embedded-in-navigation-controller.html">Bug Table View State Not Restored When Embedded In Navigation Controller</a> was originally posted 07 Apr 2013 on <a href="http://useyourloaf.com">http://useyourloaf.com</a>. Copyright 2013 Keith Harrison.</p>]]></description>
    </item>
    
    <item>
		  <title>Downloading Old iOS SDK Documentation</title>
		  <link>http://useyourloaf.com/blog/2013/04/05/downloading-old-ios-sdk-documentation.html</link>
      <pubDate>Fri, 05 Apr 2013 16:08:00 +0100</pubDate>
		  <guid>http://useyourloaf.com/blog/2013/04/05/downloading-old-ios-sdk-documentation.html</guid>
      
        <category>Xcode</category>
      
      <description><![CDATA[<p><em>I recently did a clean install of Xcode 4.6.1 on a new Mac and found I was missing some of the earlier iOS 4.x and 5.x documentation sets. This post shows how to get that older documentation back should you need it.</em></p>

<h3>Xcode Documentation Sets</h3>

<p>Xcode Documentation Sets (&#8220;docsets&#8221;) are packaged as standard OS X bundles and updated via an RSS or Atom feed. It is beyond the scope of this post but you can find more details on how to integrate your own documentaion with Xcode in the Apple <a href="https://developer.apple.com/library/ios/documentation/DeveloperTools/Conceptual/Documentation_Sets/">Documentation Set Guide</a>.</p>

<p>A clean install of Xcode will download and install the docsets for the current versions of iOS, OS X and Xcode. For example, Xcode 4.6.1 which is the current version available in the Mac App Store at time of writing includes feed subscriptions to the docsets for iOS 6.1, OS X 10.8 and Xcode 4.6:</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-04-05-001.png" alt="" /></p>

<p>The documentation for the most commonly used iOS and Mac OS X developer libraries can be downloaded and installed from the Downloads pane of the Xcode preferences (⌘,).</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-04-03-001.png" alt="" /></p>

<p>Unfortunately since in my case I have recently done a clean install on a new machine I am missing some of the earlier iOS 4.x and 5.x documentation sets.</p>

<h3>Adding Old Docsets to Xcode</h3>

<p>As long as you know the URL of the docset feed you need it is easy to add it back to Xcode. If you have access to an older install of Xcode on a different machine which has the missing docsets you can use it to find the feed URL&#8217;s. Luckily even if you cannot find the feed you need on another installation it is not too difficult to guess the URL.</p>

<p>From the Documentation tab of the Xcode Downloads preferences pane you can check the URL of a selected docset in the lower information window. In the example below I have highlighted the feed URL for the iOS 6.1 docset:</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-04-05-002.png" alt="" /></p>

<p>The following URL&#8217;s cover the most common iOS docsets (I have shown them as http:// but you can also specify https:// or even feed://):</p>

<pre><code>http://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone6.1.atom
http://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone6.0.atom
http://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone5_1.atom
http://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone5_0.atom
http://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone4_3.atom
http://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone4_2.atom
http://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone4_1.atom
</code></pre>

<p>To subscribe to a docset you need to use the small &#8220;+&#8221; button in the middle of the window (see previous screenshot). Copy and paste the required URL into the dialog and click the Add button. You should then see the new feed in the list of docsets and you can click the Install button to download it.</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-04-05-003.png" alt="" /></p>

<h3>Manually Download a docset</h3>

<p>If for some reason you want to download the docset without using Xcode you can manually fetch the feed and use it to get the direct URL to the docset archive. For example to manually retrieve the iOS 4.3 docset, first retrieve the atom feed using <code>curl</code> and grep for the link elements in the feed (note that I am using https as the http link is actually just a redirect):</p>

<pre><code>$ curl https://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone4_3.atom | grep link
    &lt;link rel="self" href="http://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone4_3.atom"&gt;&lt;/link&gt;
    &lt;link rel="enclosure" type="application/octet-stream" href="http://devimages.apple.com/docsets/20110309/com.apple.adc.documentation.AppleiOS4_3.iOSLibrary.xar" length="477703763"&gt;&lt;/link&gt;
    &lt;link rel="enclosure" type="application/octet-stream" href="http://devimages.apple.com/docsets/20110720/com.apple.adc.documentation.AppleiOS4_3.iOSLibrary.xar" length="229887175"&gt;&lt;/link&gt;
</code></pre>

<p>In this case the last update to the docset in the feed was on 2011-07-20 so we can retrieve that XML archive file:</p>

<pre><code>$ curl http://devimages.apple.com/docsets/20110720/com.apple.adc.documentation.AppleiOS4_3.iOSLibrary.xar -o AppleiOS4_3.iOSLibrary.xar
</code></pre>

<p>To get the docset file package uncompress the archive using the <code>xar</code> command:</p>

<pre><code>$ xar -xf AppleiOS4_3.iOSLibrary.xar
</code></pre>

<p>If you want to view the resulting docset package in Xcode you will need to move it to the Xcode docsets directory at the following location:</p>

<pre><code>~/Library/Developer/Shared/Documentation/DocSets
</code></pre>

<h3>Uninstall Old Docsets</h3>

<p>Searching for a class or framework in the Xcode organiser can be confusing when you have lots of old documentation installed. You can end up with at least one result from each version of the documentation which means you need to be careful that you are reading the latest version.</p>

<p>Unfortunately you cannot remove an Apple docset using the &#8216;-&#8217; button in the preferences pane. If you want to uninstall an Apple docset you can instead manually delete the file from the Xcode DocSets directory. This is usually located under <code>~/Library/Developer/Shared/Documentation/DocSets</code>. You can also check the location of a docset from the documentation tab of the Downloads pane in the Xcode preferences window. Select the documentation set you want to uninstall and look in the information area at the bottom of the window.</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-04-05-004.png" alt="" /></p>

<p>If you click on the installed location of the documentation set it will open in Finder with the doc set selected. Deleting the docset file will remove it from the system.</p>

<p>Note that Xcode does not provide a way for you to completely remove the feed subscription for an Apple docset. Once you have the deleted the documentation set the &#8220;Installed&#8221; status will change back to an &#8220;Install&#8221; button which is useful should you need to download it again in the future. It does however mean that you end up with an ever longer list of historical documentation feeds.</p>

        <hr><p><a href="http://useyourloaf.com/blog/2013/04/05/downloading-old-ios-sdk-documentation.html">Downloading Old iOS SDK Documentation</a> was originally posted 05 Apr 2013 on <a href="http://useyourloaf.com">http://useyourloaf.com</a>. Copyright 2013 Keith Harrison.</p>]]></description>
    </item>
    
    <item>
		  <title>Core Data 2nd Edition by Marcus Zarra</title>
		  <link>http://useyourloaf.com/blog/2013/03/07/core-data-by-marcus-zarra.html</link>
      <pubDate>Thu, 07 Mar 2013 22:12:00 +0000</pubDate>
		  <guid>http://useyourloaf.com/blog/2013/03/07/core-data-by-marcus-zarra.html</guid>
      
        <category>core</category>
      
        <category>data</category>
      
        <category>reviews,</category>
      
      <description><![CDATA[<p><img class="right" src="http://imagery.pragprog.com/products/301/mzcd2.jpg" width="150" height="250">
<em>There are many books on general iOS development but they often only provide brief coverage of Core Data. I was therefore pleased to see that my favourite book on the topic, <a href="http://pragprog.com/book/mzcd2/core-data">Core Data, Second Edition</a> by Marcus S. Zarra (The Pragmatic Bookshelf, January 2013) has recently received a major update.</em></p>

<h3>First Impressions</h3>

<p>The first edition of Core Data by Marcus Zarra was the book I turned to when I wanted to learn Core Data. Whilst it is still a great book it was starting to get a little dated. It was also heavily biased to using Core Data on the OS X desktop platform rather than iOS. This was not such a huge problem as many of the key concepts are valid for both platforms. However the use of Core Data for iOS was restricted to a single chapter which meant that iOS specific issues and features such as <code>NSFetchedResultsController</code> got only a brief mention.</p>

<p>The second edition has been substantially updated and the change in emphasis is evident from the change in subtitles of the two editions. The first edition was subtitled <em>Apple&#8217;s API for Persisting Data on Mac OS X</em> where for the 2nd Edition it is <em>Data Storage and Management for iOS, OS X and iCloud</em>. The growing army of iOS developers has had an impact:</p>

<blockquote><p>The largest number of Objective-C developers develop only for iOS, and therefore we will keep our focus there.</p></blockquote>

<p>It is also worth mentioning that the book covers the latest updates to the Core Data framework as shipped with iOS 6 and OS X 10.8. In fact, Marcus goes as far as to recommend not using the newest Core Data API&#8217;s if you need backward compatibility:</p>

<blockquote><p>However, iOS 5.0 (and Mac OS X 10.7) was a stumble, a misstep. It is far better to skip it and move on to iOS 6.0. But what about when your client/boss/customer requires you to be compatible with iOS 5.0? My advice is to use only the Core Data APIs that were available in iOS 4.x.</p></blockquote>

<h3>In Depth</h3>

<p>The first half of the book provides an in depth coverage of the key concepts of Core Data. The example code is for an iOS application and a whole chapter is dedicated to covering <code>NSFetchedResultsController</code> reflecting the new focus of the book.</p>

<p>The next three chapters on Core Data versioning and migration, performance tuning and threading are all essential reading. Even if you consider yourself a Core Data expert there is a lot of good practical advice here. The treatment of <em>migrations</em> covers both lightweight and heavy migrations with sufficient detail to understand why heavy migrations can be a headache. The discussion on <em>performance tuning</em> has good advice about handling binary data and also on when to denormalize data. This is a good lesson to learn if you are coming to Core Data with an SQL database background. Finally the chapter on <em>threading</em> covers how to use Core Data in a way that is thread safe.</p>

<p>This expanded and updated edition now also provides a detailed discussion of using Core Data with iCloud. This covers both the traditional Core Data stack and the newer UIManagedDocument API. Marcus does mention the problems Apple has had getting this to work reliably:</p>

<blockquote><p>Unfortunately, as has been demonstrated numerous times in the past, syncing is hard, very hard. Apple did not get it working acceptably in iOS 5.0 or OS X 10.7. It was not until iOS 6.0 and OS X 10.8 that iCloud has become truly reliable.</p></blockquote>

<p>I still do not feel confident syncing the standard Core Data stack with iCloud even with iOS 6.0. The known issue when the user turns off iCloud is covered and a number of experienced developers are still <a href="http://www.macworld.com/article/1167742/developers_dish_on_iclouds_challenges.html">reporting issues</a>. Hopefully when Apple do finally fix it Marcus will update the book with the details.</p>

<p>The second half of the book moves to using Core Data with OS X. If you are primarily an iOS developer this can still be interesting reading. Firstly because you should realise that you already know much of what is required. Secondly you can get a deeper understanding of some key technologies (if you will excuse the pun) such as KVC and KVO when used on the desktop platform.</p>

<p>The last three chapters of the book are somewhat bonus material. There is a discussion on how to integrate Core Data with Spotlight and Quick Look on the desktop. A further example of using KVC to store dynamic paramaters and an &#8220;academic&#8221; investigation on remotely accessing a Core Data repository using Bonjour. Interesting reading but not essential to understanding Core Data.</p>

<h3>Likes and Dislikes</h3>

<p>There is not much to dislike. This is one of those books that works well both for introductory and advanced audiences. If you are new to Core Data the basics are covered to get you up to speed. On the other hand if you have been using Core Data for a while you can jump straight to the chapters on migrations, performance and threading and learn something.</p>

<p>I have a preference for technical books that are written by experienced practitioners with a strong point of view. I don&#8217;t want a book that simply reformats the information in Apple&#8217;s documentation. The parts of this book that I like best are when Marcus is giving us his opinion on how to get the best from Core Data and what you should avoid. Overall a great book that just got better.</p>

<h3>Final Comments</h3>

<p>You can buy the dead-tree version of the book from the usual places but I prefer to get the ebook version direct from the <a href="http://pragprog.com/book/mzcd2/core-data">pragprog.com</a> web site. A final tip if you want more Marcus Zarra on Core Data I can also recommend the videos he has done with Scotty over at <a href="http://ideveloper.tv/">iDeveloper TV</a>.</p>

        <hr><p><a href="http://useyourloaf.com/blog/2013/03/07/core-data-by-marcus-zarra.html">Core Data 2nd Edition by Marcus Zarra</a> was originally posted 07 Mar 2013 on <a href="http://useyourloaf.com">http://useyourloaf.com</a>. Copyright 2013 Keith Harrison.</p>]]></description>
    </item>
    
    <item>
		  <title>Xcode 4.6 Recommended Build Settings</title>
		  <link>http://useyourloaf.com/blog/2013/03/03/xcode-4-dot-6-recommended-build-settings.html</link>
      <pubDate>Sun, 03 Mar 2013 15:26:00 +0000</pubDate>
		  <guid>http://useyourloaf.com/blog/2013/03/03/xcode-4-dot-6-recommended-build-settings.html</guid>
      
        <category>LLVM</category>
      
        <category>Xcode</category>
      
      <description><![CDATA[<p>Xcode 4.6 introduced a number of additional compiler warnings that are enabled by default for new projects. Unfortunately the <a href="https://developer.apple.com/library/mac/#releasenotes/DeveloperTools/RN-Xcode/">release notes</a> are none too clear about the new options:</p>

<blockquote><p>LLVM: New compiler warnings to help find subtle behavioral bugs when using automatic release counting (ARC) and weak references.</p></blockquote>

<p>If you have an existing project you can update to the new recommended build settings from the project page using the &#8220;Validate Settings&#8221; button:</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-02-13-001.png" alt="" /></p>

<p>A diff with the Xcode <code>project.pbxproj</code> file checked into source control reveals the changed settings:</p>

<pre><code>CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
</code></pre>

<p>If you check the build settings for the project you will find three of the new settings in the <em>Apple LLVM compiler 4.2 - Warnings - All languages</em> section:</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-03-03-001.png" alt="" /></p>

<p>The remaining setting is in the <em>Apple LLVM compiler 4.2 - Warnings - Objective C</em> section:</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-03-03-002.png" alt="" /></p>

<p>A useful tip here to get a detailed description for a build setting is to have the quick help window open in the utilities sidebar when clicking on each setting.</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-03-01-001.png" alt="" /></p>

<h3>New Project Build Settings</h3>

<p>For the purposes of this post I have been using one of the example projects (WorldFacts) from my <a href="https://github.com/kharrison/CodeExamples/tree/master/WorldFacts">GitHub CodeExamples</a> repository which was created back in June 2012. From the date I would guess that means I was probably using Xcode 4.3.3. Out of curiosity I compared the build settings after updating this project with a clean new project created with Xcode 4.6. There seems to be one additional compiler warning that is enabled by default for the new Xcode 4.6 project that the validate settings option does not enable for existing projects:</p>

<blockquote><p>Empty Loop Bodies: Warn about loop bodies that are suspiciously empty.   [CLANG_WARN_EMPTY_BODY, -Wempty-body]</p></blockquote>

<p>It is possible this was already a default for new projects prior to Xcode 4.6 and I have never noticed. It does seem strange though that the validate settings option does not update it for existing projects. Anyway since I would probably like to know about suspiciously empty loop bodies I have also enabled it for the existing project.</p>

<p><em>What follows is a more detailed description of each of the four new Xcode 4.6 compiler warning build settings. In each case I have included the detailed description from the help documentation for reference.</em></p>

<h3>Implicit Constant Conversions</h3>

<p><em>Warn about implicit conversions of constant values that cause the constant value to change, either through a loss of precision, or entirely in its meaning.  [CLANG_WARN_CONSTANT_CONVERSION, -Wconstant-conversion]</em></p>

<p>This catches problems such as the following where a constant is converted to a type that causes the value to change:</p>

<pre><code>int8_t smallInt = 500;
Implicit conversion from 'int' to 'int8_t' (aka 'signed char') changes value from 500 to -12

NSInteger value = 4294967296;
Implicit conversion from 'long long' to 'NSInteger' (aka 'int') changes value from 4294967296 to 0
</code></pre>

<h3>Implicit Enum Conversions</h3>

<p><em>Warn about implicit conversions between different kinds of enum values.  For example, this can catch issues when using the wrong enum flag as an argument to a function or method.  [CLANG_WARN_ENUM_CONVERSION, -Wenum-conversion]</em></p>

<p>For an example, suppose I have two somewhat similar enum types defined for a class:</p>

<pre><code>typedef enum
{
  UYLMagicUser = 0,
  UYLMagicAdmin = 1
} UYLMagicValue;

typedef enum
{
  UYLNonMagicUser = 10,
  UYLNonMagicAdmin = 11
} UYLNonMagicValue;
</code></pre>

<p>A method that is expecting a UYLMagicValue as an argument:</p>

<pre><code>- (void)doSomeMagic:(UYLMagicValue)magicType
{
  //
}
</code></pre>

<p>Most of the time Xcode autocompletion will guide you to the right value when calling this method but it is still easy to end up with the following by mistake:</p>

<pre><code>[self doSomeMagic:UYLNonMagicAdmin];
</code></pre>

<p>Assuming that I had actually intended to pass UYLMagicAdmin this is going to end in disappointment. With the new compiler warning enabled  you get the following:</p>

<pre><code>Implicit conversion from enumeration type 'UYLNonMagicValue' to different enumeration type 'UYLMagicValue'
</code></pre>

<h3>Incompatible Integer to Pointer Conversion</h3>

<p><em>Warn about implicit conversions between pointers and integers.  For example, this can catch issues when one incorrectly intermixes using NSNumber&#8217;s and raw integers.  [CLANG_WARN_INT_CONVERSION, -Wint-conversion]</em></p>

<p>This warning works either way when there is an implicit conversion between integers and pointers:</p>

<pre><code>char smallInt = @"1";
Incompatible pointer to integer conversion initializing 'char' with an expression of type 'NSString *'

char *pointer = 1234;
Incompatible integer to pointer conversion initializing 'char *' with an expression of type 'int'
</code></pre>

<h3>Duplicate Method Definitions</h3>

<p><em>Warn about declaring the same method more than once within the same @interface.</em></p>

<p>This is a pretty simple one that picks up multiple definitions of the same method in an interface definition:</p>

<pre><code>@interface UYLMyClass ()
- (void)someRandomMethod:(NSString *)name;
// Lots of other stuff...
// and more...
- (void)someRandomMethod:(NSString *)name;
@end
Multiple declarations of method 'someRandomMethod:' found and ignored
</code></pre>

<h3>One last thing</h3>

<p>If you are still using the LLVM-GCC compiler or GDB debugger you should also note the following warning in the Xcode 4.6 release notes and start thinking about adopting LLVM/LLDB in the near future:</p>

<blockquote><p>DEPRECATED: LLVM-GCC compiler and GDB debugger.
Xcode 4.6 is the last release to include the LLVM-GCC compiler and the GDB debugger.</p>

<p>Use the LLVM compiler and the LLDB debugger, and file reports at https://bugreport.apple.com for issues that require the use of LLVM-GCC or GDB.</p></blockquote>

        <hr><p><a href="http://useyourloaf.com/blog/2013/03/03/xcode-4-dot-6-recommended-build-settings.html">Xcode 4.6 Recommended Build Settings</a> was originally posted 03 Mar 2013 on <a href="http://useyourloaf.com">http://useyourloaf.com</a>. Copyright 2013 Keith Harrison.</p>]]></description>
    </item>
    
    <item>
		  <title>Apple Webpage Touch Icons</title>
		  <link>http://useyourloaf.com/blog/2013/02/23/apple-webpage-icons.html</link>
      <pubDate>Sat, 23 Feb 2013 22:32:00 +0000</pubDate>
		  <guid>http://useyourloaf.com/blog/2013/02/23/apple-webpage-icons.html</guid>
      
        <category>HTML</category>
      
        <category>Safari,</category>
      
      <description><![CDATA[<p>Mobile Safari allows you to add an icon to the home screen of a device for any web page you visit using the share button. The screen shot below shows the icon that is used if you do this for apple.com.</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-02-24-001.png" alt="Add to Home Screen" /></p>

<p>If your website does not supply an icon it will use a screenshot of the page which will often look less then impressive. You will also see a lot of failed requests for the file <code>apple-touch-icon.png</code> in the error logs for the web site which can be annoying. If you have a web site that you expect to be visited by users with an Apple device (which I guess is most sites) you should probably spend a few minutes to make that icon look good on the users device.</p>

<h3>Webpage Touch Icons</h3>

<p>The ever growing range of Apple devices with different form factors and screen resolutions makes keeping track of the various icon files you need no easy task. At the time of writing the list of icons file sizes for each device type is as follows:</p>

<ul>
<li>apple-touch-icon.png (57x57 iPhone and iPod touch)</li>
<li>apple-touch-icon-72x72.png (72x72 iPad 1st and 2nd gen)</li>
<li>apple-touch-icon-114x114.png (114x114 retina iPhone and iPod touch)</li>
<li>apple-touch-icon-144x144.png (144x144 retina iPad)</li>
</ul>


<p>The filenames listed above are the default names you should use if you are relying on Safari to find the icon files in your website root directory.</p>

<p>The icon with the most appropriate size for the device will be used if present. The rules for which icon will be used in cases where the preferred size is not available are a little complicated. In theory the next largest is used if present or failing that the largest icon is used. This means that you could just create a single icon of 144x144 pixels and it will be downloaded and resized by the browser as required. However this is a little wasteful given that it does not take much effort to just create each of the icon sizes I listed previously.</p>

<p>By default Safari will also add rounded corners and a glossy shine effect to the icon similar to the way application icons are treated. The ability to specify a precomposed image which will not be modified was introduced in iOS 2.0. If you do not want Safari to mess with the image you can add &#8220;precomposed&#8221; to the filename (e.g. <code>apple-touch-icon-precomposed.png</code>). If you supply both a normal and precomposed version of an icon Safari will use the precomposed version.</p>

<h3>Webpage Touch Icon Links</h3>

<p>Rather than relying on Safari searching the root directory of a site you can also explicitly specify the icon files to use in a link element added to the head section of the web page. This can also be useful if you need to name the files differently from the default names or if you want different icons to be used for different pages within a site.</p>

<p>Using the same filenames as before a full set of links would look as follows:</p>

<pre><code>&lt;link rel="apple-touch-icon" sizes="144x144" href="http://useyourloaf.com/apple-touch-icon-144x144.png" /&gt;
&lt;link rel="apple-touch-icon" sizes="114x114" href="http://useyourloaf.com/apple-touch-icon-114x114.png" /&gt;
&lt;link rel="apple-touch-icon" sizes="72x72" href="http://useyourloaf.com/apple-touch-icon-72x72.png" /&gt;
&lt;link rel="apple-touch-icon" href="http://useyourloaf.com/apple-touch-icon.png" /&gt;
</code></pre>

<p>For completeness if you do not want Safari to add any image effects the links would be as follows:</p>

<pre><code>&lt;link rel="apple-touch-icon-precomposed" sizes="144x144" href="http://useyourloaf.com/apple-touch-icon-144x144-precomposed.png" /&gt;
&lt;link rel="apple-touch-icon-precomposed" sizes="114x114" href="http://useyourloaf.com/apple-touch-icon-114x114-precomposed.png" /&gt;
&lt;link rel="apple-touch-icon-precomposed" sizes="72x72" href="http://useyourloaf.com/apple-touch-icon-72x72-precomposed.png" /&gt;
&lt;link rel="apple-touch-icon-precomposed" href="http://useyourloaf.com/apple-touch-icon-precomposed.png" /&gt;
</code></pre>

<h3>Browser Compatibility</h3>

<p>The situation gets a little more complicated if you care about supporting older versions of iOS or other mobile browser platforms (e.g. Android, Blackberry, Microsoft). For Safari the only real issue is if you need to support devices running anything earlier than iOS 4.2 which do not support specifying icons with different sizes. For that situation it is a good idea to always include <code>apple-touch-icon-precomposed.png</code> and <code>apple-touch-icon.png</code> files as a fallback.</p>

<p>Other browsers have varying levels of support for the Apple way of doing things.
For more on cross-browser compatibility issues and recommendations see this <a href="http://mathiasbynens.be/notes/touch-icons">excellent article</a>. Some general guidelines that I end up with:</p>

<ul>
<li>Always use the Apple defined names rather than custom names.</li>
<li>Always place the icon files in the document root if possible.</li>
<li><p>I prefer the precomposed variation but also include <code>apple-touch-icon.png</code> as a fallback. For example, this site has the following icon files in the document root:</p>

<pre><code>apple-touch-icon-72x72-precomposed.png
apple-touch-icon-114x114-precomposed.png
apple-touch-icon-144x144-precomposed.png
apple-touch-icon-precomposed.png
apple-touch-icon.png
</code></pre></li>
<li><p>Include the link elements in the page head section in addition to having the files in the standard location.</p></li>
</ul>


        <hr><p><a href="http://useyourloaf.com/blog/2013/02/23/apple-webpage-icons.html">Apple Webpage Touch Icons</a> was originally posted 23 Feb 2013 on <a href="http://useyourloaf.com">http://useyourloaf.com</a>. Copyright 2013 Keith Harrison.</p>]]></description>
    </item>
    
    <item>
		  <title>Open With Menu Duplicates</title>
		  <link>http://useyourloaf.com/blog/2013/01/01/open-with-duplicates.html</link>
      <pubDate>Tue, 01 Jan 2013 12:24:00 +0000</pubDate>
		  <guid>http://useyourloaf.com/blog/2013/01/01/open-with-duplicates.html</guid>
      
        <category>osx</category>
      
      <description><![CDATA[<p>I have for some time been suffering a minor (but it seems not uncommon) annoyance with the &#8220;Open With&#8221; menu when I right click on a document in the Finder. Over time a number of old and duplicate items have worked there way into the list. It seems that OS X has at some point spotted additional copies of applications and helpfully added them to the menu. VMWare Fusion has also made a contribution adding some applications from an old Windows XP image before I figured out how to disable that option. The following is what I was seeing when I right-clicked on a <code>pdf</code> file:</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-01-01-001.png" alt="duplicate open with" /></p>

<p>Now I like Pixelmator and Evernote but there is no way I really want to see them listed five times and I have never wanted to open a pdf using Internet Explorer. I cannot say for sure when I first noticed this problem but I do know it is worse since I upgraded to Mountain Lion.</p>

<h3>Launch Services</h3>

<p>The Launch Services API is what controls how a running application can open a document in another application. When you open a file in the Finder what actually happens under the covers is that the Finder uses the Launch Services API to request that the associated application is used to open the file on behalf of the user.</p>

<p>In order to be able to respond to such requests Launch Services maintains a database in which it records all registered applications and the kinds of documents each application can open. (If you are curious you can find this database in <code>~/Library/Preferences/com.apple.LaunchServices.plist</code>.) The system takes care of registering applications with Launch Services automatically in the following situations:</p>

<ul>
<li>When the system boots or a new user logs in the Applications directory is scanned and any new applications are registered.</li>
<li>The Finder will automatically register any new applications as it &#8220;becomes aware of them&#8221; such as when they are installed.</li>
<li>When the user opens a document which does not have a preferred application registered in the launch services database they will be asked to select one by the Finder which is then registered for future use.</li>
</ul>


<p>Luckily you do not really need to know anything about Launch Services to clean up the &#8220;Open With&#8221; menu.</p>

<h3>Command-Line Utility - lsregister</h3>

<p>The easiest way to interact with the launch services database is to use the <code>lsregister</code> command-line utility from the terminal. Unfortunately it is buried deep down in a system library subdirectory:</p>

<pre><code>$ cd /System/Library/Frameworks/CoreServices.framework/Versions/Current/Frameworks/LaunchServices.framework/Versions/Current/Support/
</code></pre>

<p>You can of course just search from the command-line if you are having problems finding it on older versions of OS X:</p>

<pre><code>$ find /System/Library/Frameworks -name lsregister
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister
</code></pre>

<p>The two directory paths although slightly different are actually equivalent as the <code>Current</code> directory is actually just a link to the <code>A</code> directory. Whichever path you use once you have set it as your current working directory you can reset the database with the following command:</p>

<pre><code>$ ./lsregister -kill -r -all system,local,user
</code></pre>

<p>Notes:</p>

<ul>
<li><p>The above commands were tested on OS X Mountain Lion (v10.8.2), earlier OS versions stored the lsregister command in different locations and used different command-line options (see below).</p></li>
<li><p>If you google for &#8220;lsregister&#8221; or for &#8220;Open With Duplicates&#8221; you will find that most people will recommend the following command to reset the launch services database.</p>

<pre><code>$ ./lsregister -kill -r -domain system -domain local -domain user
</code></pre>

<p>As far as I can tell the two command-line variations are equivalent and do the same thing. The latter of the two (using -domain) no longer appears as a valid command-line option (use ./lsregister -h to see all options) but still works as of Mountain Lion (v10.8.2). If you running an earlier version of OS X you may need to use this variation.</p></li>
<li><p>I did not find it necessary to restart the Finder or reboot for the changes to take effect but your mileage may indeed vary.</p></li>
<li><p>If you add the -v option for verbose output to the above lsregister command you can watch as the system library and application directories are scanned and each application is registered. Do not be alarmed by the -10811 error messages, they are just indicating that a non-application file or directory was found and could not be registered which is harmless.</p>

<pre><code>  ...
  lsregister: registered /Applications/Twitterrific.app
  lsregister: error -10811 registering /Applications/Utilities
  lsregister: error -10811 registering /Applications/Utilities/.DS_Store
  lsregister: error -10811 registering /Applications/Utilities/.localized
  lsregister: registered /Applications/Utilities/Activity Monitor.app
  ...
</code></pre></li>
</ul>


<h3>Finally Back To Normal</h3>

<p>After resetting the launch services database my &#8220;Open With&#8221; menu is finally back to a clean and useful size. The following is what I now see for a <code>pdf</code> file:</p>

<p><img src="http://useyourloaf.com/assets/images/2013/2013-01-01-002.png" alt="clean open with" /></p>

<p>Several days later my menu is still looking clean so I am hoping it will now stay that way. Unfortunately it seems that this is a long standing OS X problem even though it only seems to have recently started to annoy me.</p>

        <hr><p><a href="http://useyourloaf.com/blog/2013/01/01/open-with-duplicates.html">Open With Menu Duplicates</a> was originally posted 01 Jan 2013 on <a href="http://useyourloaf.com">http://useyourloaf.com</a>. Copyright 2013 Keith Harrison.</p>]]></description>
    </item>
    
    <item>
		  <title>Supporting the 4-inch Retina Display</title>
		  <link>http://useyourloaf.com/blog/2012/12/31/retina-4-support.html</link>
      <pubDate>Mon, 31 Dec 2012 15:10:00 +0000</pubDate>
		  <guid>http://useyourloaf.com/blog/2012/12/31/retina-4-support.html</guid>
      
        <category>retina</category>
      
      <description><![CDATA[<p>It already seems a long time ago that the iPhone 5 and iPod touch (5th generation) devices were released with the 4-inch retina display. Better late than never I finally get around in this post to sharing my notes on the often minimal changes required to support the new screen dimensions.</p>

<h3>Letterbox Mode</h3>

<p>If you make no modifications to an existing app it will still work on the new devices but displays in a letterbox with black bars at the top and bottom of the app. The following screenshots show an unmodified version of my <a href="https://github.com/kharrison/CodeExamples/tree/master/WorldFacts">World Facts example app</a> in both portrait and landscape orientations running on the larger 4-inch device (in this case a 5th gen iPod touch):</p>

<p><img src="http://useyourloaf.com/assets/images/2012/2012-12-30-001.png" alt="letterbox portrait" />
<img src="http://useyourloaf.com/assets/images/2012/2012-12-30-002.png" alt="letterbox landscape" /></p>

<p>The sinking feeling I get when I see an App displaying in letterbox mode reminds me of when the iPad launched and many apps would only run in 2x mode.</p>

<h3>Retina 4 Launch images</h3>

<p>If you have an app using standard view controllers without any custom drawing or artwork it turns out there is very little you need to do to support the new screen dimensions other than add a new launch image. The iOS Human Interface Guidelines give the required dimensions to use:</p>

<blockquote><p>For apps that run on iPhone 5 and iPod touch (5th generation), create a launch image that measures 640 x 1136 pixels.</p></blockquote>

<p>You can also find details in the iOS App Programming Guide include the naming convention for the default filename:</p>

<blockquote><p>To specify default launch images for iPhone 5 and iPod touch (5th generation) devices, include the modifier string -568h immediately after the <basename> portion of the filename. Because these devices have Retina displays, the @2x modifier must always be included with launch images for the devices.</p></blockquote>

<p>If you open an existing app in a recent version of Xcode (4.5.2 at time of writing) you will get a build issue that also shows you the required filename:</p>

<pre><code>Retina 4 Support: Missing "Default-568h@2x.png" launch image.
</code></pre>

<p>Clicking on the issue in the navigator will display a dialog with Xcode offering to add the missing launch image for you:</p>

<p><img src="http://useyourloaf.com/assets/images/2012/missingretina4launchimage.png" alt="missing retina 4 launch image" /></p>

<p>If you accept and allow Xcode to add the missing launch image it will add a file named <code>Default-586h@2x.png</code> to the project with dimensions of 640 x 1136 pixels. This will work but the image that is added to the project is a plain black background which does not match our initial user interface very well. Since I never previously bothered to add any launch images (or icons) to this example app I will add three of my own launch images as follows:</p>

<ul>
<li>Default.png - 320 x 480 pixels (standard resolution iPhone)</li>
<li>Default@2x.png - 640 x 960 pixels (high resolution iPhone 4)</li>
<li>Default-568h@2x.png - 640 x 1136 pixels (iPhone 5)</li>
</ul>


<p>The launch image consists of a 20 pixel high (40 pixel for high resolution) status bar, a 44 pixel high title bar (88 pixel for high resolution) and then a white content area. Since this is an iPhone only app we do not need to worry about iPad or landscape launch images. Once added to Xcode the three launch images should show up in the target summary screen of the project (if you prefer you can just drap and drop the images onto the relevant placeholder to have Xcode add the files to the project for you):</p>

<p><img src="http://useyourloaf.com/assets/images/2012/2012-12-31-001.png" alt="xcode launch image" /></p>

<p>With the correct launch image in place the application should now make full use of the larger 4-inch screen:</p>

<p><img src="http://useyourloaf.com/assets/images/2012/2012-12-31-002.png" alt="screenshot" /></p>

<h3>Auto-sizing</h3>

<p>One issue that can cause problems on the larger 4-inch screen is that a view may not correctly resize to the taller screen size. Assuming you have not yet migrated to auto-layout the auto-sizing springs and struts must be set correctly to allow each view to grow in height.</p>

<p><img src="http://useyourloaf.com/assets/images/2012/2012-12-31-003.png" alt="autosizing" /></p>

<p>This is something that is easy to overlook when testing so be sure to check each view on an actual device. In this case I already had the main table view set correctly to fill the content area so everything just worked.</p>

<h3>Wrapping up</h3>

<p>As the iOS device family grows so does the list of image assets and resources required. Whilst it will not be so simple for all apps in this case supporting the 4-inch retina display only required adding one new launch image. What continues to be important is to thoroughly test on a real device.</p>

<p>The modified example Xcode project that accompanies this post can be found in my GitHub <a href="https://github.com/kharrison/CodeExamples/tree/master/WorldFacts">Code Examples repository</a>. Since I am posting this on the last day of 2012 I will also take the opportunity to wish you all a happy new year!</p>

        <hr><p><a href="http://useyourloaf.com/blog/2012/12/31/retina-4-support.html">Supporting the 4-inch Retina Display</a> was originally posted 31 Dec 2012 on <a href="http://useyourloaf.com">http://useyourloaf.com</a>. Copyright 2013 Keith Harrison.</p>]]></description>
    </item>
    
    <item>
		  <title>Presenting View Controllers</title>
		  <link>http://useyourloaf.com/blog/2012/10/08/presenting-view-controllers.html</link>
      <pubDate>Mon, 08 Oct 2012 21:01:00 +0100</pubDate>
		  <guid>http://useyourloaf.com/blog/2012/10/08/presenting-view-controllers.html</guid>
      
        <category>viewController</category>
      
      <description><![CDATA[<p>It has been a long time since I posted about about <a href="http://useyourloaf.com/blog/2010/05/03/ipad-modal-view-controllers.html">iPad Modal View Controllers</a>. The last couple of years has seen the introduction first of iOS 5 and storyboards and now iOS 6. This has in turn seen the old methods for presenting and dismissing modal views controllers discouraged and now formally deprecated. So I think it is time for a quick update on what has changed and how to migrate old code.</p>

<h3>Modal The Old Fashioned Way</h3>

<p>In the good old days of iOS 3.2 and iOS 4 if you wanted to create a modal view controller you would do so with code that looked something like this:</p>

<pre><code>DetailViewController *viewController = [[DetailViewController alloc]
                                       initWithNibName:@"DetailViewController"
                                                bundle:nil];
viewController.delegate = self;
UINavigationController *navController = [[UINavigationController alloc]
                                        initWithRootViewController:viewController];
[self presentModalViewController:navController animated:YES];
</code></pre>

<p>This code fragment is taking from the old iOS 3.2 era post on <a href="http://useyourloaf.com/blog/2010/05/03/ipad-modal-view-controllers.html">iPad Modal View Controllers</a> but is fairly typical. The user interface XIB file is first created by Interface Builder and then used to instantiate the new view controller.</p>

<p>In this example the view controller is embedded in a navigation controller but the key to presenting the modal view controller is the call to presentModalViewController:animated:. A similar call to dismissModalViewControllerAnimated: in the presenting view controller takes care of removing the modal view controller.</p>

<p>The modalPresentationStyle property controls whether the view controller is presented full screen, as a page or form sheet on the iPad. Likewise the modalTransitionStyle property controls how the new view animates onscreen.</p>

<h3>Presented and Presenting View Controllers</h3>

<p>With iOS 5 Apple started to deprecate the modal view controller methods and replace them with the more general concept of presenting and presented view controllers. The modal view controller being the presented view controller. Conceptually not much has changed and if you adopt storyboards it gets even easier. Consider a trivial two view controller application represented by the following storyboard:</p>

<p><img src="http://useyourloaf.com/assets/images/2012/2012-10-08-001.png" alt="storyboard" /></p>

<p>The root view contains three buttons each of which is wired to trigger a different modal segue to the presented view controller. The three segues have unique identifiers and specify both the modal presentation and transition styles in the storyboard. For example here is the storyboard segue for the full screen button:</p>

<p><img src="http://useyourloaf.com/assets/images/2012/2012-10-08-002.png" alt="full screen segue" /></p>

<p>The page sheet segue which is full screen height but uses the portrait screen width when in landscape is specified as follows:</p>

<p><img src="http://useyourloaf.com/assets/images/2012/2012-10-08-003.png" alt="page sheet segue" /></p>

<p>Finally the form sheet segue which uses both a view height and width smaller than full screen is specified as follows:</p>

<p><img src="http://useyourloaf.com/assets/images/2012/2012-10-08-004.png" alt="form sheet segue" /></p>

<p>If you are not using storyboards and creating a separate NIB file for the presented view controller you will need to implement a method for the various UIButton actions that creates and presents the new controller manually. For example, the method triggered when the full screen button is tapped would look something like this:</p>

<pre><code>- (IBAction)selectedFullScreen:(UIButton *)sender
{
  UYLPresentedViewController *viewController = [[UYLPresentedViewController alloc]
                                               initWithNibName:@"UYLPresentedViewController"
                                                        bundle:nil];
  viewController.delegate = self;
  viewController.modalPresentationStyle = UIModalPresentationFullScreen;
  [self presentViewController:viewController animated:YES completion:NULL];
}
</code></pre>

<p>Note the call to presentViewController:animated:completion:. The completion argument can take a block which is called after the viewDidAppear: method of the presented view controller. Specify NULL if you do not need the completion handler.</p>

<h3>Dismissing Presented View Controllers</h3>

<p>Not much has changed when it comes to dismissing modal view controllers other than the name of the method you should use. Best practise suggests that you arrange for the presenting view controller to dismiss the presented view controller which generally means setting up a delegate protocol. This is nothing new but for completeness I will show a typical interface for a presented view controller:</p>

<pre><code>@protocol UYLPresentedViewControllerDelegate &lt;NSObject&gt;
- (void)didDismissPresentedViewController;
@end

@interface UYLPresentedViewController : UIViewController
@property (nonatomic, weak) id&lt;UYLPresentedViewControllerDelegate&gt; delegate;
@end
</code></pre>

<p>The UYLPresentedViewController class defines a protocol that we expect all users of the class to adopt. It has a single mandatory method that will be called when we determine that the presented view controller will be dismissed. If you need to pass data back to the presenting view controller you could add an argument to this method. The public interface definition of the class includes a weak reference to the delegate.</p>

<p>The done button in the presented view controller is then wired to call the following action method when it is touched:</p>

<pre><code>- (IBAction)didSelectDone:(UIButton *)sender
{
  [self.delegate didDismissPresentedViewController];
}
</code></pre>

<p>The presenting view controller needs to adopt the protocol:</p>

<pre><code>@interface UYLViewController : UIViewController &lt;UYLPresentedViewControllerDelegate&gt;
</code></pre>

<p>It also needs to set itself as the delegate which is not something we can do directly in the storyboard. Instead we need to implement prepareForSegue:sender: as follows to retrieve the newly instantiated view controller and set the delegate:</p>

<pre><code>- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
  if ([segue.identifier isEqualToString:UYLSegueFullScreen] ||
      [segue.identifier isEqualToString:UYLSeguePageSheet] ||
      [segue.identifier isEqualToString:UYLSegueFormSheet])
  {
    UYLPresentedViewController *viewController = segue.destinationViewController;
    viewController.delegate = self;
  }
}
</code></pre>

<p>With the delegate set we can complete the implementation of didDismissPresentedViewController.</p>

<pre><code>- (void)didDismissPresentedViewController
{
  [self dismissViewControllerAnimated:YES completion:NULL];
}
</code></pre>

<p>Note that we now call dismissViewControllerAnimated:completion: instead of dismissModalViewControllerAnimated:. The completion handler in this case if specified is called after the viewDidDisappear: method is called on the presented view controller.</p>

<p>If defining the delegate protocol seems like a lot of work for such a trivial example you can take a short cut. The UIViewController class now has two properties to indicate both the presentedViewController and the presentingViewController. We could use this to dismiss the view controller directly from the presented view controller. For example we could change our UIButton action method to the following:</p>

<pre><code>- (IBAction)didSelectDone:(UIButton *)sender
{
  [self.presentingViewController dismissViewControllerAnimated:YES completion:NULL];
}
</code></pre>

<p>This achieves the same effect without the need to define and set a delegate but in general I prefer the fuller approach of keeping the presentation and dismissal all in the presenting view controller. The use of delegation also makes it easier when you need to pass data back to the presenting view controller.</p>

<h3>Migration</h3>

<p>As of the time of writing this post the presentModalViewController:animated: and dismissModalViewControllerAnimated: methods do still exist in iOS 6 but are deprecated and will generate Xcode compilation warnings. If you are starting a new project today and you can target iOS 5 or later you should just use the new methods. Likewise if you have an existing app that uses the deprecated methods now is a good time to think about updating assuming you no longer require iOS 4.</p>

<p>If you have already made the switch to using storyboards for the user interface you may find that you have already eliminated the calls to presentModalViewController:animated:. As I showed above the storyboard takes care of instantiating and presenting the view controller for you.</p>

<p>However since with storyboards you still need to take care of dismissing the view controller you may have some calls to dismissModalViewControllerAnimated: buried in your view controller code. The migration in this case is trivial since you can generally replace these with dismissViewControllerAnimated: as I described above.</p>

<h4>Updated: 10-Oct-2012</h4>

<p>As was pointed out in the comments the code as originally posted for dismissing the presented (modal) view controller from within the presented view controller contained a mistake. The dismissViewControllerAnimated:completion: method should of course be called on self.presentingViewController. A further comment pointed out some unnecessary code in the didSelectDone method that was checking the value of self.delegate which is unnecessary since a method call on nil is harmless. The code snippets in the post have been updated accordingly.</p>

        <hr><p><a href="http://useyourloaf.com/blog/2012/10/08/presenting-view-controllers.html">Presenting View Controllers</a> was originally posted 08 Oct 2012 on <a href="http://useyourloaf.com">http://useyourloaf.com</a>. Copyright 2013 Keith Harrison.</p>]]></description>
    </item>
    
    <item>
		  <title>VoiceOver Bug and iOS 5 TableViews Revisited</title>
		  <link>http://useyourloaf.com/blog/2012/09/11/voiceover-bug-and-ios-5-tableviews-revisited.html</link>
      <pubDate>Tue, 11 Sep 2012 19:18:00 +0100</pubDate>
		  <guid>http://useyourloaf.com/blog/2012/09/11/voiceover-bug-and-ios-5-tableviews-revisited.html</guid>
      
        <category>VoiceOver</category>
      
        <category>iOS 5</category>
      
        <category>tableviewcontroller</category>
      
      <description><![CDATA[<p>Unfortunately I need to revisit the previous post about an iOS 5 bug that was preventing <a href="http://useyourloaf.com/blog/2012/09/07/prototype-table-view-cells-not-working-with-voiceover.html">prototype table view cells working with VoiceOver</a>. After posting I realised I had not quite done enough to work around the problem when using storyboards.</p>

<h3>The Problem</h3>

<p>In a nutshell there is a known bug in iOS 5 when VoiceOver is active which causes calls to the <code>UITableView</code> method <code>dequeueReusableCellWithIdentifier:</code> to fail to return a table view cell. I experienced this bug when playing with prototype cells created by a storyboard but I should be clear that the bug is not directly related to either storyboards or prototype cells (though it does have some extra impact for storyboards). You can experience the problem even if you not using storyboards and simply using a standard UITableView cell style:</p>

<pre><code>- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  static NSString *CellIdentifier = @"SubtitleCell";

  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
  if (cell == nil)
  {
    NSLog(@"Failed to dequeue cell");
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
                                  reuseIdentifier:CellIdentifier];
  }
  // configure cell
  return cell;
}
</code></pre>

<p>With VoiceOver active on an iOS 5 device the above code will <em>always</em> fail to dequeue a cell and fall through to the cell allocation code (logging &#8220;Failed to dequeue cell&#8221;). Of course if you have registered a NIB with the table view you may be surprised when you do not get back a cell and crash. Hence my original workaround which was to always test that a cell is returned and manually allocate when VoiceOver is active.</p>

<h3>Everlasting Cells</h3>

<p>One of the impacts of this bug is that when VoiceOver is active table view cells never get reused. This means that as the table view is scrolled new cells are constantly being allocated. This is clearly visible in Instruments if you scroll
a table view whilst running on an iOS 5 device with VoiceOver active. If you have very large table view cells and do lots and lots of scrolling you could in theory run out of memory. In practise I would guess that table view cells are small enough that normal table view activity is not sufficient to cause a serious problem.</p>

<h3>Broken Seques</h3>

<p>There is one other impact of this bug when using Storyboards that I missed when first attempting a workaround in my example storyboard app, WorldFacts. My initial attempt was simply to load the custom country cell from a separate XIB file using UINib method <code>instantiateWithOwner:options:</code>. This appeared to work but unfortunately since this new cell was not loaded via the storyboard it is not associated with any of the segues defined in the storyboard. This means that tapping a row in the table with VoiceOver active does nothing. The seque to the detailed country view controller is never triggered.</p>

<p>I think the reason I did not immediately spot this problem is that it does not occur if you activate VoiceOver when the table view cells have already been created from the storyboard. The easiest way to reproduce the problem is to ensure that VoiceOver is active before the App is launched.</p>

<h3>Manually Triggering A Segue</h3>

<p>To trigger the segue for the cells we have created with VoiceOver active we could just simply perform the required segue with <code>performSegueWithIdentifier:sender:</code> in the table view delegate method <code>tableView:didSelectRowAtIndexPath:</code>. However we need to be careful not to manually trigger the segue for normally created cells as the storyboard will also perform the segue for those cells.</p>

<p>To avoid triggering the seque twice I ended up using a different cell identifier for the cells that I am manually creating when VoiceOver is active. So my final implementation of <code>tableView:cellForRowAtIndexPath:</code> starts as follows:</p>

<pre><code>- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:UYLCountryCellIdentifier];
</code></pre>

<p>This is the original cell creation using the cell identifier (<code>UYLCountryCellIdentifier</code>) for the prototype cell registered in the storyboard. In normal conditions this will always return a cell but with VoiceOver active on iOS 5 it returns nil.</p>

<pre><code>  if (cell == nil)
  {
    cell = [self.tableView dequeueReusableCellWithIdentifier:UYLNibCountryCellIdentifier];

    if (cell == nil)
    {
        [self.countryCellNib instantiateWithOwner:self options:nil];
        cell = self.countryCell;
        self.countryCell = nil;
    }
  }
</code></pre>

<p>When I fail to get a cell from the storyboard I then attempt to dequeue a cell with the identifier (<code>UYLNibCountryCellIdentifier</code>) of the cell in the registered XIB file. This is of course futile since with VoiceOver active it will also fail. Finally I instantiate a new cell using the cached UINib object (refer to the previous post for further details).</p>

<p>Once we have identified our manually created cells we can implement the table view delegate method <code>tableView:didSelectRowAtIndexPath:</code> to manually trigger the segue to the detailed view for just these cells:</p>

<pre><code>- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
  if ([cell.reuseIdentifier isEqualToString:UYLNibCountryCellIdentifier])
  {
    [self performSegueWithIdentifier:UYLSegueShowCountry sender:cell];
  }
}
</code></pre>

<p>Note that once we have called <code>performSequeWithIdentifier:sender:</code> for our manually allocated cell we end up back at the <code>prepareForSegue:sender:</code> method as for a correctly created cell and the view transition completes.</p>

<h3>All Done</h3>

<p>I hope that really is everything now to workaround this annoying bug when using storyboards. Unfortunately even with the imminent release of iOS 6 it seems likely that we will have to live with this bug for as long as iOS 5 support is required. See my <a href="https://github.com/kharrison/CodeExamples">GitHub CodeExamples</a> repository for the updated <a href="https://github.com/kharrison/CodeExamples/tree/master/WorldFacts">WorldFacts App</a>.</p>

        <hr><p><a href="http://useyourloaf.com/blog/2012/09/11/voiceover-bug-and-ios-5-tableviews-revisited.html">VoiceOver Bug and iOS 5 TableViews Revisited</a> was originally posted 11 Sep 2012 on <a href="http://useyourloaf.com">http://useyourloaf.com</a>. Copyright 2013 Keith Harrison.</p>]]></description>
    </item>
    
  </channel>
</rss>