Lecture #7: iPad Apps

Please note, this blog entry is from a previous course. You might want to check out the current one.

Lecture seven is named “7. iPad Apps (October 18, 2011)” and can be found at iTunes. Its slides are available at Stanford.

It starts by discussing UIToolbar and its UIBarButtonItems which are stored in an NSArray *toolbarItems. A bottom toolbar – which is hidden by default – can be made visible via storyboard or setting its @property toolbarHidden to NO.

UISplitViewController are only available for the iPad and provide a master on the left and a detail view on the right hand side and are provided as NSArray *viewControllers (0 = master, 1 = detail). As this property is passed as copy it is not possible to use it to manipulate the view controller directly.

In portrait mode, the master normally disappears. Thus a delegate is necessary for its accessibility best set in in viewDidLoad of the UIViewController. Using

- (BOOL)splitViewController:(UISplitViewController *)sender
   shouldHideViewController:(UIViewController *)master

it is possible

  • to hide the master view always by returning YES,
  • to show the maser view always by returning NO, or
  • to hide it only in portrait mode by returning UIInterfaceOrientationIsPortrait(orientation).

When the master view is hidden, the delegate must provide a way to make it visible again, which can be realized in

- (void)splitViewController:(UISplitViewController *)sender
     willHideViewController:(UIViewController *)master
          withBarButtonItem:(UIBarButtonItem *)barButtonItem
       forPopoverController:(UIPopoverController *)popover

To remove this again, e.g. in landscape mode when the master is shown anyway, use

- (void)splitViewController:(UISplitViewController *)sender
     willShowViewController:(UIViewController *)master
  invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem

A typical way would be putting a button into the toolbar:

- (void)setSplitViewBarButtonItem:(UIBarButtonItem *)barButtonItem 
    UIToolbar *toolbar = [self toolbar];
    NSMutableArray *toolbarItems = [toolbar.items mutableCopy];
    if (_splitViewBarButtonItem) 
        [toolbarItems removeObject:_splitViewBarButtonItem];
    if (barButtonItem) 
        [toolbarItems insertObject:barButtonItem atIndex:0];
    toolbar.items = toolbarItems;
    _splitViewBarButtonItem = barButtonItem;

When the detail view is replaced by another view, it is essential to transfer this bar button to the new view, otherwise the master might get inaccessible:

- (id)splitViewDetailWithBarButtonItem
    id detail = [self.splitViewController.viewControllers lastObject];
    if ([detail respondsToSelector:@selector(setSplitViewBarButtonItem:)] &&
        [detail respondsToSelector:@selector(splitViewBarButtonItem)]) {
        return detail;
    return nil; 

- (void)transferSplitViewBarButtonItemToViewController:(id)destinationViewController
    UIBarButtonItem *splitViewBarButtonItem = 
        [[self splitViewDetailWithBarButtonItem] splitViewBarButtonItem];
    [[self splitViewDetailWithBarButtonItem] setSplitViewBarButtonItem:nil];
    if (splitViewBarButtonItem) 
        [destinationViewController setSplitViewBarButtonItem:splitViewBarButtonItem];
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    if ([segue.identifier isEqualToString:@"MyReplaceSegue"]) {
        [self transferSplitViewBarButtonItemToViewController:segue.destinationViewController];
        [segue.destinationViewController setSomeProperty:self.dataToTransferToDetail];

Popovers display a UIViewController inside a rectangle on screen. Its change can be animated via setContentViewController:animated:. popoverVisible tells if it is visible. A popover can be created in storyboard but also in code via presentPopoverFromRect:, presentPopoverinView: or presentPopoverFromBarButtonItem: and needs a strong pointer. It is dismissed if the user clicks outside the popover, or in code via dismissPopoverAnimated:. A delegate gets notified on dismissal.

Universal applications provide a single binary image for iPhone and iPad with storryboards for different layouts. They are setup at the creation of the project, but might also by changing the Devices pull down under the Summary tab to Universal later on.

It know on which device an app is currently running different solutions are possible, e.g.

BOOL iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);

or check for an existing splitViewController which is only available on an iPad.

The second part of the lecture provides a demo changing the psychologist app to be universal and use split views. The code for this demo is available directly at Stanford as well as code for additional features which where not shown in the demo due to lack of time, or at github.


Leave a Reply

Your email address will not be published.