Wednesday, August 5, 2015

Exploring Multitasking on the iPad Air in Swift

Introduction

I was intrigued when I saw the demonstrations of multitasking on the iPad running under iOS 9 in the 2015 WWDC sessions. The iPad Air 2 can run two apps at the same time. The second app can slide over the first, or they can run side by side in a split view. You can only run one instance of any particular app at a time.

The iPad Air only supports running in a slide over pane.

Starting a second app is simple. Here is the Calendar app in landscape.


Swipe in from the right edge. The first time you will get a list of the apps that support multitasking. The next time you will get the app you used most recently with the current app.


Here I've chosen the Feedback app. It slides over the Calendar app, which is full screen behind it. If you tap on the Calendar app the feedback app slides away.


If you want to go back and forth without having to swipe, tap on the divider between the apps.


You can bring back the list of apps by dragging it down from the top.

You can drag the divider into the center of the screen so the two apps take up equal space.


Multitasking is more awkward when you rotate the iPad to portrait. You don't usually see Portrait mode in demonstrations. I think it might be better to rotate the individual applications in place, but that creates other design issues.


Ars Technica has a nice video demonstrating this. It doesn't show portrait.

How to Support Multitasking

It seemed simple enough to support. There are only three criteria:
  • Build your app with the iOS9 SDK.
  • Support all four orientations: Portrait, Upside Down, Landscape Left, and Landscape Right.
  • Use a storyboard for the launch screen.

Writing a Sample Program

I decided to write a sample program to explore what happens to an application under multitasking in iOS 9. I immediately realized that I needed to write two sample apps so I could see both sides change together.

Adaptive One and Adaptive Two

I wanted to write one app that could run on both sides at once. I couldn't do that, so I did the next best thing. I wrote two apps that share the important parts of the code; the main storyboard file and the view controller.
  1. Create a workspace. I named mine Adaptive.
  2. Create two applications within the workspace. I named mine Adaptive One and Adaptive Two. I turned off source control for each. I wanted one repository containing both projects and their shared files.
  3. Then I deleted the main storyboard and the view controller from each app. When Xcode asked if "Do you want to move to the Trash, or only remove the reference to it?" I answered "Trash" for Adaptive One and "reference" for Adaptive Two.
  4. I then used Finder to move the unreferenced storyboard and Swift source files from Adaptive Two to a new folder under the Workspace that I named Adaptive Common.
  5. I then added the two files to each app as existing files. I made sure to uncheck "Copy items if needed". I wanted each file to be shared by both applications.
  6. I then created a git repository for the entire workspace. From terminal I changed to the folder containing the workspace file Adaptive.xcworkspace. I then executed two git commands:
          git init
          git add .

This created a workspace that contains both projects, the common files, and the Adaptive.xcworkspace file. Xcode recognized the repository after it restarted.

The Adaptive apps display basic information about the current size classes, the scale, UI idiom, and the bounds.  It also has a text input field so you can experiment with multitasking and the keyboard.


The app updates the horizontal and vertical size classes and the user interface idiom in 

override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?)

It updates the window height and width in

override func viewWillTransitionToSize(size: CGSize,
        withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator)

The source is available on GitHub at: https://github.com/bwake2012/Adaptive