MacKuba

Kuba Suder's blog on Mac & iOS development

Introducing Multiple Windows on iPad

Categories: UIKit, WWDC 19 0 comments Watch the video

The user should be able to do everything from a single window if they want to – if your app *requires* using multiple windows, then something is wrong

In most apps there will be only one kind of window – you should be able to move from every starting point in each window to every other place in the app

An example of an app that has different kinds of windows is Mail, where you can open a new window for a composed message, but it’s a window dedicated to that new message and you can’t get back to the list inside it

Another example is Messages where you can pull out a conversation to a new window, and it’s a window only for that conversation

In every document-based app (e.g. Pages) the user may have the expectation that they can work with different documents in different windows

In non-document apps like Maps or Calendar you will also often want to be able to do two different things, see two different contexts or scenarios at the same time, and now you can do that by opening two windows

Ways to create a new window:

  • in the app expose, there’s a “+” button in the corner that creates new windows
  • when you have the app open and you drag its icon from the dock to the side, it creates a second window
  • in a lot of places in your app it might make sense to hold & drag an element like a tab to the side and create a window from it, but for that you need to implement drag & drop. Whenever you have a place where the user can drag & drop something and it would make sense to make a window from the dragged thing, it should be possible.
  • a common example is any master-detail view like Mail, where you can drag any list row (email) out to a new window
  • explicit action like an “Open in New Window” action in a context menu

UIWindowScene:

  • contains the user interface (UIWindow) of a single “window”
  • it’s created on demand for you and destroyed when unused

UISceneSession:

  • represents the state in which the UI in a given window is or was last time when it was persisted

Difference between scene and session: scenes are released to save memory, and when the user sees 4 windows of the app in the switcher, it’s possible that only one of them is currently active in memory – the others are stored as persisted sessions, and when selected in the switcher, they will be “unfreezed” and assigned a scene again

UIApplicationDelegate gets split up:

  • UIApplicationDelegate still processes lifecycle events about the whole app
  • UIApplication still stores the state of the whole app
  • any lifecycle events that concern only a specific scene are instead handled by UIWindowSceneDelegate using UIWindowScene & UISceneSession
  • methods like application will enter foreground/background, applicationDidFinishLaunching, application open URL etc. go to scene delegate

New state restoration API based on NSUserActivity:

  • UISceneSession.stateRestorationActivity
  • UISceneSession.persistentIdentifier – can be used to integrate with custom state restoration code
  • UISceneSession.userInfo – for storing simple settings like what element is currently selected or what mode an element is in
  • SceneDelegate: stateRestorationActivity(for scene:) -> NSUserActivity?
  • SceneDelegate: scene(_: willConnectTo session: options:) – initializer like in UIApplicationDelegate, options include userActivities for activities passed e.g. from Handoff
  • AppDelegate: application(_: didDiscardSceneSessions:) – use this if needed to clean up saved data for a session when it gets destroyed

How to implement multi-window support:

  1. 1. Check “Supports multiple windows” in the target settings
  2. 2. Set up Scene Configuration / Application Session Role list in Info.plist with one or more session roles (name of delegate class and storyboard file)
  3. 3. Implement the two necessary delegate methods in UIWindowSceneDelegate
  4. 4. If needed, add ways to create new windows, e.g. using drag & drop or custom buttons

APIs in UIApplication to programatically manage sessions:

  • requestSceneSessionActivation(_:userActivity:options:errorHandler:) – creates a new scene for a given user activity, or activates an existing session
  • requestSceneSessionRefresh(_:) – requests an update to a scene
  • requestSceneSessionDestruction(_:options:errorHandler:) – deletes a scene (you can select one of 3 animations)

Be prepared for this change to check some assumptions you might have made, that there will be only one instance of a given VC at a time etc… :)

Watch out for global variables, singletons and other shared data

Keeping UserDefaults up to date between scenes: use KVO observation on UserDefaults

UIApplication statusBar* and keyWindow methods and open(_: options: completionHandler:) callback are deprecated, replaced by equivalents on UIWindowScene (statusBarManager, interfaceOrientation)

  • this is even for apps that will not use multiple scenes


Leave a comment

*

*
This will only be used to display your Gravatar image.

*

What property can you use on iOS to get a unique device ID that the user can reset in Settings?

*