Hour 11. Implementing Multiple Scenes and Popovers


What You’ll Learn in This Hour:

Image How to create multiple scenes in the storyboard

Image The use of segues to transition between scenes

Image Ways to transfer data between scenes

Image How to present and use popovers


This hour marks a major milestone in your iOS app development capabilities. In the preceding hour’s lesson, you learned about alert views and action sheets. These were the first user interface (UI) elements we’ve explored that act as (somewhat) independent views that a user interacts with. You’ve also seen how to hide and show views, making it possible to customize your user interface. All of these, however, took place within a single scene. That means that no matter how much was going on onscreen, we used a single view controller and a single initial view to deal with it. In this hour, we break through those limits and introduce the ability to create applications with multiple scenes—in other words, multiple view controllers and multiple views.

In this lesson, you learn how to create new scenes and the new view controller classes you need to back them up. You also learn how to visually define your transitions between scenes and trigger them automatically, or programmatically. In addition, you will explore the use of popovers to present information within a pseudo “window” on the display.

Before we begin, I want to add a disclaimer: In this hour, you learn several different ways to accomplish the same thing. Apple changes the iOS often, and despite their somewhat elegant software development kit (SDK), you will encounter inconsistencies. The takeaway is that you should do what you feel comfortable with. There are plenty of “clever” solutions to problems that result in code that, although correct, is never going to make sense to anyone but the person who wrote it.

Introducing Multiscene Storyboards

We’ve been able to build apps that do quite a few things using a single view, but many don’t lend themselves to a single-view approach. It’s rare to download an app that doesn’t have configuration screens, help screens, or other displays of information that go beyond the initial view that is loaded at runtime.

To use features like these in your apps, you need to create multiple scenes in your storyboard file. Recall that a scene is defined by the presence of a view controller and a view. You’ve been building entire applications in one view with one view controller for the past six hours. Imagine how much functionality you could introduce with unlimited scenes (views and view controllers). With the iOS project storyboard, that’s exactly what you can do.

Not only that, but you can literally “draw” the connections between different scenes. Want to display an information screen if the user touches a Help button? Just drag from your button to a new scene. It “just works.” Figure 11.1 shows a multiscene application design with segues.

Image

FIGURE 11.1 A multiscene application design.

The Terminology

Before we head into multiscene development, we should introduce/review a few pieces of terminology, several of which you’ve learned previously but may not have really had to think about until now:

Image View controller: A class that manages the user’s interactions with his iDevice. In many of the tutorials in this book, single-view controllers are used for most of the application logic, but other types exist (and are used in the coming hours).

Image View: The visual layout that a user sees onscreen. You’ve been building views in view controllers for quite awhile now.

Image Scene: A unique combination of view controller and view. Imagine you’re building an image-editing application. You may choose to develop scenes for selecting files to edit, another scene for implementing the editor, another for applying filters, and so on.

Image Segue: A segue is a transition between scenes, often with a visual transition effect applied. There are multiple types of segues available depending on the type of view controller you’re using.

Image Exit: The Exit icon appears in each scene in your storyboard. The exit can be used to transition back to a previous scene. If you display four scenes in sequence, for example, and want to move from the fourth back to the first, you would use the first scene’s exit.

Image Unwind: The process of moving back to an earlier scene by way of the exit. This is considered an “unwind” segue.

Image Modal views: A modal view is one that is displayed over top of an original view when user interactions are required. You will mostly be using modal views (by way of the modal segue type) in this book.

Image Relationship: A “segue” of sorts for certain types of view controllers, such as the tab bar controller. Relationships are created between buttons on a master tab bar that display independent scenes when touched. You learn about these in Hour 13, “Advanced Storyboards Using Navigation and Tab Bar Controllers.”

Image Storyboard: The file that contains the scene, segue, and relationship definitions for your project.

You must create new class files to support the requirement for multiple view controllers; so, if you need a quick refresher on adding new files to Xcode, refer to Hour 2, “Introduction to Xcode and the iOS Simulator.” Other than that, the only prerequisite is the ability to Control-drag, something you should be very good at by now.

Preparing a Multiscene Project

To create an application with multiple scenes and segues, you must first know how to add new view controller and view pairings to your project. For each of these, you also need supporting class files where you can code up the logic for your additional scenes. To give you a better idea of how this works, let’s use a typical Single View Application template as a starting point.

As you’re well aware, the Single View Application template has a single view controller and a single view (in other words, a single scene). This doesn’t mean, however, that we’re stuck with that configuration. You can expand a single view application to support as many scenes as you want; it just provides us with a convenient starting point.

Adding Additional Scenes to a Storyboard

To add a new scene to a storyboard, open the storyboard file (Main.storyboard) in the Interface Builder (IB) editor. Next, make sure that the Object Library (Control-Option-Command-3) is open and type view controller in the Search field to show the view controller objects that are available, as shown in Figure 11.2.

Image

FIGURE 11.2 Find the view controller objects in the Object Library.

Next, drag the view controller into an empty portion of IB editor area. The view controller will add itself, with a corresponding view, to your storyboard, and just like that, you’ll have a new scene, as shown in Figure 11.3. You can drag the new view around in the storyboard editor to position it somewhere convenient. By default, the new view controller’s simulated size will not be set. Once you connect it to another view via a segue, however, it automatically inherits that view’s simulated size.

Image

FIGURE 11.3 Adding a new view controller/view creates a new scene.


Note

If you find it difficult to grab and drag the new view around in the editor, use the object dock above it. It provides a convenient handle for moving the object around.


Naming Scenes

After adding a new scene, you’ll notice there’s a bit of a problem brewing in the document outline area (Editor, Show Document Outline). By default, each scene is named based on its view controller class. We’ve been using a view controller class called ViewController, so the document outline shows the default scene as View Controller Scene. Once we add a new scene, it doesn’t have a view controller class assigned yet, so it also appears as View Controller Scene. Add another, and that scene also appears as View Controller Scene (and so on).

To deal with the ambiguity, you have two options: First, you can add and assign view controller classes to the new scenes. We’re going to do this anyway, but sometimes it’s nicer to have a plain English name for a scene that can be anything we want without it reflecting the underlying code. (“John’s Awesome Image Editor Scene” makes a horrible name for a view controller class.) The second option is to label a scene using any arbitrary string you want. To do this, select its view controller in the document outline, and then open the Identity Inspector and expand the Document section, as shown in Figure 11.4. Use the Label field to enter a name for the scene. Xcode automatically tacks Scene onto the end, so there’s no need to add that.

Image

FIGURE 11.4 Label the view controller to help differentiate between scenes.

An even faster approach is to select the View Controller line in the Document Outline and press Return; the item is then immediately editable directly in the outline. You can apply this practice to the view controller to set the scene name, or to any objects within the scene to set easy-to-understand labels.

Adding Supporting View Controller Subclasses

After establishing the new scenes in your storyboard, you need to couple them to actual code. In the Single View Application template, the initial view’s view controller is already configured to be an instance of the ViewController class—implemented by editing the ViewController.swift file. We need to create similar files to support any new scenes we add.


Note

If you’re just adding a scene that displays static content (such as a Help or About page), you don’t need to add a custom subclass. You can use the default class assigned to the scene, UIViewController, but you won’t be able to add any interactivity.


To add a new subclass of UIViewController to your project, make sure that the project navigator is visible (Command-1), and then click the + icon at the bottom-left corner of the window. When prompted, choose iOS, the Source category, then Cocoa Touch Class, and click Next. Now, select a subclass of UIViewController, as shown in Figure 11.5. You’ll also be asked to name your class. Name it something that differentiates it from other view controllers in your project. EditorViewController is better than ViewControllerTwo, for example. Make sure that Language is set to Swift, and then click Next.

Image

FIGURE 11.5 Choose the UIViewController subclass.

Finally, you’re prompted for where to save your new class. Use the group pop-up menu at the bottom of the dialog to choose your main project code group, and then click Create. Your new class is added to the project and ready for coding, but it still isn’t connected to the scene you defined.

To associate a scene’s view controller with the UIViewController subclass, shift your attention back to the IB editor. Within the document outline, select the view controller line for the new scene, and then open the Identity Inspector (Option-Command-3). In the Custom Class section, use the drop-down menu to select the name of the class you just created (such as EditorViewController), as shown in Figure 11.6.

Image

FIGURE 11.6 Associate the view controller with the new class.

After the view controller is assigned to a class, you can develop in the new scene exactly like you developed in the initial scene, but the code will go in your new view controller’s class. This takes us most of the way to creating a multiscene application, but the two scenes are still completely independent. If you develop for the new scene, it’s essentially like developing a new application; there is no way for the scenes to work together and no way to transition between them.

Creating a Segue

Creating a segue between scenes uses the same Control-drag mechanism that you have (hopefully) become very fond of over the first half of this book. For example, consider a two-scene storyboard where you want to add a button to the initial scene that, when clicked, will transition to the second scene. To create this segue, you Control-drag from the button to the second scene’s view controller (targeting either the visual representation of the scene itself, or the view controller line in the document outline), as shown in Figure 11.7.

Image

FIGURE 11.7 Control-drag from the object to the new scene’s view controller.

When you release your mouse button, a Storyboard Segues box appears, as shown in Figure 11.8. Here you can choose the type of segue that you’re creating, most likely Present Modally or Popover Presentation.

Image

FIGURE 11.8 Choose the segue type to create.

A total of five options appear:

Image Show: Create a chain of scenes where the user can move forward or back. This is used with navigation view controllers, which we look at in Hour 13.

Image Show Detail: Replace the current scene with another. This is used in some view controllers, such as popular the split-view controller. We’ll look at this in Hour 14, “Navigating Information Using Table Views and Split View Controllers.”

Image Present Modally: Transition to another scene for the purposes of completing a task. When finished, we dismiss the scene, and it transitions back to the original view. This or the Popover Presentation is the segue you’ll use most often.

Image Popover Presentation: Displays the scene in a pop-up “window” over top of the current view on some devices (such as the iPad) or as a sliding modal view on others (iPhone).

Image Custom: Used for programming a custom transition between scenes.

For most projects, you’ll want to choose a modal or popover transition, which is what we use here. The other segues are used in very specific conditions and do not work unless those conditions are met. If that piques your interest, good; you’ll see more of these over the next few hours.


Note: Adaptive Segues

The segues listed here are known as adaptive segues in iOS 8. That means that they’ll adapt to whatever platform they’re running on. While you’ve been targeting iPads or iPhones independently, this “adaptive” nature will make creating universal applications much easier later in the book (and, to be honest, later in this hour—but that’s a surprise).

You’ll see additional segues listed as being “deprecated” when linking your view controllers. These are the “old” (nonadaptive) way of doing things and should be avoided for your shiny new apps.



Tip

You can create a segue that isn’t attached to any particular UI element by Control-dragging from one scene’s view controller to another. Doing so creates a segue that you can trigger, in your code, from a gesture or other event.


After adding the segue to your project, you’ll see a line added to the editor area that visually ties your two scenes together. You can rearrange the individual scenes within the editor to create a layout that maps how the application will flow. This layout is solely for your benefit; it doesn’t change how the application will operate.

You’ll also notice a representation of it in your document outline. The scene that is initiating a segue will show a new line “<Segue name> to <destination>” in the outline. Selecting the segue line gives us the opportunity to configure an identifier (seen in Figure 11.9) and several other settings.

Image

FIGURE 11.9 Set an identifier or change the type of segue being used.

The identifier is an arbitrary string that you can use to trigger a segue manually or identify which segue is underway programmatically (if you have multiple segues configured). Even if you don’t plan to use multiple segues, it’s a good idea to name this something meaningful (toEditor, toGameView, and so on).

The Segue drop-down appears on any segue you’ve added and enables you to switch between segue types at will. Depending on the type of segue you’ve chosen, you’ll have a few additional options to set. Let’s start with the most common type: modal segues.

Configuring Modal Segues

Modal segues offer many different settings for controlling the appearance of the destination view controller as it is displayed on the screen. When viewing a modally presented segue in the Attributes Inspector, you’ll see two drop-downs—presentation and transition, visible in Figure 11.10. These options can dramatically alter how your scenes appear to the user.

Image

FIGURE 11.10 Configure each segue you add.

As mentioned earlier, segues adapt to the device the application is running on. At present, most of the presentation settings will only result in a display difference on the iPad. The iPad has more screen real estate than an iPhone, so it can do things a little differently. You have four presentation style options:

Image Full Screen: Sizes the view so that it covers the full screen.

Image Current Context: Uses the same style display as the scene that is displaying it.

Image Page Sheet: Sizes the scene so that it is presented in the portrait format.

Image Form Sheet: Sizes the scene smaller than the screen (regardless of orientation), showing the original scene behind it. This, for all intents and purposes, is the equivalent of a window.

The transition type is a visual animation that is played as iOS moves from one scene to another. You have four options here (as shown in Figure 11.10):

Image Cover Vertical: The new scene slides up over the old scene.

Image Flip Horizontal: The view flips around horizontally, revealing the new scene on the “back.”

Image Cross Dissolve: The old scene fades out while the new scene fades in.

Image Partial Curl: The old scene curls up like a piece of paper, revealing the new scene underneath.


Caution: Choose Your Styles Carefully!

Not all styles are compatible with all transitions. A page curl, for example, can’t take place on a form sheet that doesn’t completely fill the screen. Attempting to use an incompatible combination will result in a crash. So if you’ve chosen a bad pair, you’ll find out pretty quickly (or you could review the documentation for the transition/style you plan to use).


The default transition—cover vertical—presents the new view by sliding it up over the initial view. This is perfectly acceptable, but I encourage you to try the other transitions for some nifty interactive effects. The partial curl, for example, can be moved with a finger to reveal more content, as demonstrated in Figure 11.11.

Image

FIGURE 11.11 Modally presented segues offer a wide range of appearance options.

Configuring the Popover Segue

Popovers are variation on modal segues that display content on top of an existing view, with a small indicator that points to an onscreen object, such as a button, to provide context. Popovers are everywhere in the iPad interface, from Mail to Safari, as demonstrated in Figure 11.12.

Image

FIGURE 11.12 Popovers are everywhere in the iPad UI.

Using a popover enables you to display new information to your users without leaving the screen you are on, and to hide the information when the user is done with it. There are few desktop counterparts to popovers, but they are roughly analogous to tool palettes, inspector panels, and configuration dialogs. In other words, they provide UIs for interacting with content on the screen, but without eating up permanent space in your UI.

What makes a popover different from a modally presented view is that it also requires an additional controller object, a popover controller (UIPopoverPresentationController). The controller determines the source view of the popover and where it points. When the user is done with the popover, touching outside of its visible rectangle automatically closes the view.

Preparing Popovers

To create a popover, follow the exact same steps as when creating a modally presented segue. Control-drag from the element you want to display a popover to the view controller providing the popover content. When prompted for the type of storyboard segue, as shown in Figure 11.13, choose Popover Presentation.

Image

FIGURE 11.13 Set the segue type to Popover Presentation.

What makes the popover presentation attractive for any project is that when you create a popover segue and deploy it to the iPhone, it will be presented as a modally presented segue. The adaptive nature of iOS segues mean that the proper interface conventions are followed regardless of the platform. When will this come in handy? When you begin creating applications that run on both iPhones and iPads—which (hint hint) might be sooner than you think.

Setting the Popover Size

The default view associated with a new iPad scene is the same size as the main application interface. When you are displaying a popover, however, the scene needs to be much smaller. Apple allows popovers up to 600 points wide, but recommends that they be kept to 320 points or less. To set the size of the popover, select the view within the popover view controller, and open the Size Inspector (Option-Command-5). Use the Width and Height fields to enter a size for the popover. After you set the size of the view, the scene’s visual representation in the IB editor changes to the appropriate size, as shown in Figure 11.14. This makes building the content view much easier.

Image

FIGURE 11.14 Edit the height and width of the popover view.


Caution: Can’t Set Your Popover Size?

If you find yourself looking at a dimmed-out size setting for the popover view, you probably haven’t yet created the popover segue. It isn’t until Xcode “knows” that you’re adding a popover scene that it unlocks the size settings.


Configuring the Presentation Directions and Passthrough Views

After setting the popover’s size, you want to configure a few attributes on the segue itself. Select the popover segue within the initiating scene, and then open the Attributes Inspector (Option-Command-4), as shown in Figure 11.15.

Image

FIGURE 11.15 Configure the popover’s behavior by editing the segue’s attributes.

Within the Storyboard Segue settings, start by setting an identifier for the popover segue. Providing an identifier makes it possible to invoke the popover programmatically, something we look into shortly. Next, choose the directions that the popover’s arrow will appear from; this determines where iOS will present the popover on the screen.

For example, if you only allow a presentation direction of left, the popover displays to the right of whatever object is invoking it.

When a popover is displayed, touching outside of it makes it disappear. If you want to exclude certain UI elements from dismissing the popover, just drag from the Passthrough field to those objects in your view.


Note

By default, a popover’s “anchor” is set when you Control-drag from a UI object to a view controller. The anchor is the object that the popover’s arrow will point to.

As with the modal segue covered earlier, you can create “generic” popover segues that aren’t anchored. Control-drag from the originating view controller to the popover content view controller and choose a popover segue when prompted. We discuss how to display one of these generic popover segues from any button in a few minutes.


That’s all you need to do to create a working popover in IB. Unlike a modal view, a popover is automatically dismissed when you touch outside of it, so you don’t even need a single line of code to create a working interactive popover.

After setting the identifier, style, transition, and presentation for a segue, you’re ready to use it. Without you writing any code, an application that has followed these steps can now present two fully interactive views and transition between them. What it cannot do, however, is interact with them programmatically. In addition, once you transition from one view to another, you cannot transition back. For that, you need some code. Let’s take a look at how you can create and trigger modal segues programmatically, and then the different ways of transitioning back—all of which require some coding.

Presenting Modal Segues Manually

Although it is easy to create segues with a single Control-drag, in several situations you have to interact with them in programmatically. If you create a segue between view controllers that you want to trigger manually, for example, you need to know how to initiate it in code. When users are done with the task in another scene, they also need a mechanism to dismiss the modal scene and transition back to the original scene. Let’s handle these scenarios now.

Starting the Segue

First, to transition to a scene using a segue that you’ve defined in your storyboard, but don’t want to be triggered automatically, you use the UIViewController instance method performSegueWithIdentifier:sender. For example, within your initial view controller, you can initiate a segue with the identifier "toMyGame" using the following line:

performSegueWithIdentifier("toMyGame", sender: self)

That’s it. As soon as the line is executed, the segue starts and the transition occurs. The sender parameter should be set to the object that initiated the segue. (It doesn’t matter what that object is.) It is made available as a variable property during the segue if your code needs to determine what object started the process.

Dismissing a Modal Scene Programmatically

After users have finished interacting with your view, you’ll probably want to provide them with a means of getting back to where they started. At present, there is no facility in modal segues to allow for this, so you must turn to code. The UIViewController method dismissViewControllerAnimated:completion can be used in either the view controller that displayed the modal scene or the modal scene’s view controller to transition back to the original scene:

self.dismissViewControllerAnimated(true, completion: nil)

The completion is an optional closure that will be executed when the transition has completed. You can learn more about closures in Hour 3, “Discovering Swift and the Xcode Playground,” and you should have used a few in the previous hour’s lesson. After you’ve dismissed a scene presented modally, control is returned to the original scene and the user can interact with it as she normally would.

What if you’ve performed several segues and want to jump back to where you started rather than just going back one? For that, you need to make use of exits and unwind segues.

Using Exits (and the Unwind Segue)

Apple has adopted the term unwinding to mean “moving backward in a storyboard.” Storyboards show the path a user takes forward through an application, but (until now) haven’t really shown a means of moving backward. In the preceding section, you learned how to move back to an earlier view controller using dismissViewControllerAnimated:completion. This will likely be the most common method you use for unwinding, but it’s hardly a flexible solution for jumping back to an arbitrary point in your storyboard.

If you’ve displayed 10 modal view controllers, one after the other, and you want to jump from the tenth back to the second, do you really need to dismiss each view controller from number 10 back to number 2? Not if you make use of exits and the unwind segue.

Preparing a View Controller for an Exit

To use an exit, you must first decide what view controller should allow exits. This is the view controller for the scene that you want to exit to not from. Although this seems a bit counterintuitive to me, just remember that you implement the exit as your destination.

After you’ve made that determination, add a new IBAction method, shown in Listing 11.1, in the view controller’s swift file.

LISTING 11.1 Setting an Exit Point


@IBAction func exitToHere(sender: UIStoryboardSegue) {
    // No code needed!
}


There are two unique things to recognize about this method. First, the name of the method can be anything you want, it just needs to have a single UIStoryboardSegue parameter. Second, you don’t have to add any implementation code to the method. It can remain entirely empty.

Once the method is in place, you can use the Exit icon in your scene.

Connecting to an Exit (Unwind Segue)

To connect to an exit, you follow almost the same process as creating a segue. First, you need something that will trigger the exit (like a button). Control-drag from that object to the Exit icon in the scene you want to exit to, as demonstrated in Figure 11.16.

Image

FIGURE 11.16 Connect to the exit.

When you release your mouse button, you’ll be asked to pick from a list of the available exit/unwind methods; choose the exit/unwind method you implemented. You’ll notice that a new unwind segue is added to the scene you are transitioning from, as shown in Figure 11.17.

Image

FIGURE 11.17 Dragging to the Exit icon creates an unwind segue.

Once the segue is in place, activating the segue will jump from the activating view controller to the controller with the exit. You can work with the exit/unwind segues exactly like any other segue—including setting an identifier, creating a manual segue (by dragging from a view controller rather than a GUI element), and executing the unwind segue programmatically.

Programming a Segue from Scratch

Xcode storyboarding has made multiscene applications much easier to create than they were in the past, but that doesn’t mean they’re the right choice for all your applications. If you’d rather go the route of programmatically presenting a scene without defining a segue at all, you certainly can. Let’s review the process.

Setting a Storyboard Identifier

After creating your storyboard scenes, but before coding anything, you must provide a storyboard identifier for the view controller you want to display programmatically. This is done by selecting the view controller instance and opening the Identity Inspector (Option-Command-3) in the IB editor. Within the Identity section of the inspector, use the Storyboard ID field to enter a simple string to identify the view controller within your application’s storyboard. Figure 11.18 shows a view controller being configured with the storyboard ID myEditor.

Image

FIGURE 11.18 Create a storyboard identifier for the view controller.

Instantiating the View Controller and View

To display a scene within a storyboard, your application will need to create a UIStoryboard object using the method storyboardWithName that references your storyboard file. This can be used to load view controllers and their associated views (that is, scenes).

For example, to create an object mainStoryboard that references the project’s Main.storyboard file, you could use the following:

let mainStorybord: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)

Next, you configure the storyboard object to instantiate the view controller that you want to transition to using the instantiateViewControllerWithIdentifier method. Assume you’ve created a UIViewController subclass named EditorViewController and set the view controller storyboard identifier to "myEditor". You can instantiate a new instance of EditorViewController as follows:

let editorVC: EditorViewController =
mainStorybord.instantiateViewControllerWithIdentifier("myEditor") as
EditorViewController

The EditorViewController instance, editorVC, is now ready to be displayed. Before that happens, however, you may want to adjust how it will appear onscreen.

Configuring the Segue Style

Earlier I covered the different transition styles and presentation types that are available for displaying modal scenes. When displaying a view controller manually, you can apply the same effects programmatically by setting the modalTransitionStyle and modalPresentationStyle view controller variable properties, respectively. For example, to configure the editorVC view controller instance, I might use this:

editorVC.modalTransitionStyle=UIModalTransitionStyle.CoverVertical
editorVC.modalPresentationStyle=UIModalPresentationStyle.FormSheet

You can choose from the same transitions and presentation styles as mentioned earlier this hour, but you need to use these constants to identify your selections:

Image Transition styles: UIModalTransitionStyle.CoverVertical, UIModalTransitionStyle.FlipHorizontal, UIModalTransitionStyle.CrossDissolve, or UIModalTransitionStyle.PartialCurl

Image Presentation styles: UIModalPresentationStyle.FormSheet, UIModalPresentationStyle.PageSheet, UIModalPresentationStyle.FullScreen, UIModalPresentationStyle.CurrentContext, UIModalPresentationStyle.OverFullScreen, UIModalPresentationStyle.OverCurrentContext, or UIModalPresentationStyle.Popover

Notice that one of the presentation styles is UIModalPresentationStyle.Popover? If you set the modalPresentationStyle to this value, you’ve effectively configured a popover segue. There are a few additional attributes you can use to choose how the popover is displayed; we’ll get to those in a few minutes.

Displaying the View Controller

The final step in programmatically displaying a view is to, well, display it. To do this, use the UIViewController method presentViewController:animated:completion from within your application’s initial view controller:

presentViewController(editorVC, animated: true, completion: nil)

The view controller and its associated scene are displayed on the screen using the transition and presentation styles you’ve selected. From here out, you can work with the scene as if it were one you displayed via a segue. You dismiss it using the same dismissViewControllerAnimated:completion method:

dismissViewControllerAnimated(true, completion: nil)


Note

In this example, we’re programmatically creating a segue to a scene. The methods we use to do this, however, refer to view controllers. Keep in mind that a scene is just a view controller and its associated view. Because we’re instantiating a view controller (with an associated view) from the project’s storyboard, we’re effectively instantiating a “scene.” We then configure the presentation of the view controller/view and display it (the same as a segue).

Although the terminology shifts when working in code, the end result is the same.


Popover Peculiarities

In the previous section, you learned how to create a modal segue (and even configure it as a popover) programmatically—but there are still some peculiarities that you must address when working with popovers. When creating one in Interface Builder, for example, you defined the direction of the popover “arrow” and what object it should point to. To do the same in code, you need to access the UIPopoverPresentationController—a special object that defines characteristics about the popover’s appearance. When you manually set options for the arrow direction and so on for a popover segue in Interface Builder, you’re actually configuring a UIPopoverPresentationController that is automatically created for you.

Let’s get back to the example of an “editor” view controller that we want to present modally. Previously we covered the steps to display it as a modal view, but if we want to configure it as popover, we might start with this code:

let editorVC: EditorViewController =
mainStorybord.instantiateViewControllerWithIdentifier("myEditor") as
EditorViewController
editorVC.modalPresentationStyle=UIModalPresentationStyle.Popover

Once we’ve setup the view controller (editorVC) and set the presentation style to a popover, we can access a UIPopoverPresentationController that iOS automatically creates for us via the variable property - popoverPresentationController:

let presentationController:UIPopoverPresentationController =
     editorVC.popoverPresentationController!

With access to the presentation controller, we can now control several aspects of the popover display and dismissal process.

Setting the Popover Arrow

To finish the popover presentation, we must determine a few things about our display. First, what object is the popover going to presented from? Any object that you add to a view is a subclass of UIView, which has a bounds variable property. Popovers are easily configured to appear from the rectangle determined by an object’s bounds; as long as you have a reference to the object displaying the popover, you’re set. If you’re triggering the popover from a UI action, the bounds property of the object that triggered the action, for example, is retrieved with this: (sender as UIView).bounds.

Although Apple’s documentation states that we only need a rectangle or a UIView (pretty much any onscreen object) to configure the source for a UIPopoverPresentationController, in practice it does not work. I lamented this fact in the last hour when working with the iPad version of the Alert Sheet style alert. To set the object that the popover will be displayed from, you must set both a sourceRect and a sourceView.

Assuming the object you’re presenting is stored in the sender variable of an IBAction, you might use the following:

presentationController.sourceRect = (sender as UIView).bounds
presentationController.sourceView = sender as UIView


Note

You could certainly cast the sender as the object it really is (such as a UIButton—we did this in the last hour), but this implementation gives us the flexibility to have any UI object trigger an action and grab its frame value.


Then, we have determined the popover’s presentation direction. Do this by choosing from these constants:

Image UIPopoverArrowDirection.Any: The popover can be presented in any direction, giving iOS the greatest flexibility in determining how the popover is displayed.

Image UIPopoverArrowDirection.Up: The arrow is only displayed pointing up, meaning that the popover appears below the object.

Image UIPopoverArrowDirection.Down: The arrow is displayed pointing down, and the popover appears above the object.

Image UIPopoverArrowDirection.Left: The arrow is displayed pointing left, and the popover appears to the right of the object.

Image UIPopoverArrowDirection.Right: The arrow is displayed pointing right, and the popover appears to the left the object.

Apple recommends that whenever possible you should use the UIPopoverArrowDirection.Any constant. You can set the popover direction by assigning the constant (or multiple constants separated by a pipe (|)) to the UIPopoverPresentationController variable attribute permittedArrowDirections. For example, to present the editorVC popover with an arrow that points either up or down, you might use the following:

presentationController.permittedArrowDirections=
    UIPopoverArrowDirection.Up | UIPopoverArrowDirection.Down

A final display parameter that you need if creating and presenting a popover manually is to set the content size of the popover. This is not set on the presentation controller; it is set by assigning the preferredContentSize variable property on the popover’s view controller. To set a popover size of 320 points wide and 400 points tall, you could type the following:

preferredContentSize = CGSizeMake(320.0, 400.0)

With the size set, the arrow directions configured, and the source location chosen, you can proceed to present the view with the presentViewController method (just like a “plain” modal segue).

There’s still one more thing that we need to chat about with regards to popover presentation. When a popover is presented, a user can dismiss it by touching outside of it. This isn’t tied to an IBAction, so how can we get ahold of the event of the user dismissing a popover? The answer is through implementing the UIPopoverPresentationControllerDelegate protocol.

Implementing the UIPopoverPresentationControllerDelegate Protocol

When I first started developing on Apple platforms, I found the terminology painful. It seemed that no matter how easy a concept was to understand, it was surrounded with language that made it appear harder than it was. A protocol, in my opinion, is one of these things.

Protocols define a collection of methods that perform a task. To provide advanced functionality, some classes, such as UIPopoverPresentationController, may require you to implement methods defined in a related protocol to add certain functionality. Doing this is called conforming to the protocol. Some protocol methods are required and others are optional; it just depends on the features you need.

To deal with the user dismissal of a popover, the class that is responding to the dismissal (usually just a view controller) should conform to the UIPopoverPresentationControllerDelegate protocol.

To declare that a class, such as a view controller, will be conforming to the UIPopoverPresentationControllerDelegate protocol, you just modify the class line in the swift file as follows:

class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {

Next, you must set the delegate of the popover presentation controller to the object implementing the protocol. If this is the same object that is creating the popover, and you already have a copy of the presentation controller in presentationController, you can just use self, as follows:

presentationController.delegate=self

Now, when the popover is dismissed, the method popoverPresentationControllerDidDismissPopover will be called from popover’s view controller. All that remains is to implement that method, as demonstrated in in Listing 11.2.

LISTING 11.2 Handling a Popover Dismissal


func popoverPresentationControllerDidDismissPopover(popoverPresentationController:
    UIPopoverPresentationController) {
    // Handle any actions you want executed here.
}


As you can see, it isn’t difficult to work with popovers programmatically, but a bit more setup is required.

Passing Data Between Scenes

You know how to create and display scenes, but there is one very critical piece of the puzzle missing: the ability to share information between the different scenes in your application. Right now, they act as entirely independent applications, which is perfectly fine if that is your intention; however, chances are, you want an integrated user experience. Let’s make that happen.

The most straightforward way for any class to exchange information with any other is through its variable properties and methods. The only trouble with this is that we need to be able to get an instance of one scene’s view controller from another, and, at present, when using a segue we create visually, this process isn’t entirely obvious.


Tip

If you create and display a scene entirely programmatically, as demonstrated in the preceding section, you already have an instance of the new scene’s view controller in your initial view controller. You can set/access variable properties on the new view controller (editorVC.myImportant-VariableProperty=<value>) before displaying it and after it is dismissed.


The prepareForSegue:sender Method

One way to get references to the view controllers in a segue is by overriding UIViewController prepareForSegue:sender method. This method is automatically called on the initiating view controller when a segue is about to take place away from it. It returns an instance of UIStoryboardSegue and the object that initiated the segue. The UIStoryboard object contains the variable properties sourceViewController and destinationViewController, representing the view controller starting the segue (the source) and the view controller about to be displayed (the destination).

Listing 11.3 shows a simple implementation of this approach. In this example, I’m transitioning from my initial view controller (an instance of ViewController) to a new view controller, which is an instance of a hypothetical EditorViewController class.

LISTING 11.3 Using prepareForSegue:sender to Grab the View Controllers


override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let startingViewController:ViewController =
        segue.sourceViewController as ViewController

    let destinationViewController:EditorViewController =
        segue.destinationViewController as EditorViewController
}


In this implementation, I declare two constants (startingViewController and destinationViewController) to reference the source and destination controllers. Then, I assign them to typecast versions of the source and destination variable properties returned by the UIStoryboardSegue. I have to typecast the view controllers so that Xcode knows what type of object they are; otherwise, I wouldn’t be able to access their variables and methods. Of course, the source view controller is also just self, so this is a bit of a contrived example.

Once we have a reference to the destination view controller, however, we can set and access variable properties on it, even changing the presentation and transition styles before it is displayed. If it is assigned to a variable property, it can be accessed anywhere within the source view controller.

What if we want the destination view controller to send information back to the source? In this case, only the source can communicate with the destination, because that’s where the prepareForSegue:sender method is implemented. One option is to create a variable property on the destination controller that stores a reference to the source controller. Another approach, however, is to use built-in variable properties of UIViewController that make working with modally presented scenes easy, easy, easy.

The Easy Way

The prepareForSegue:sender gives us a generic way to work with any segue that is taking place in an application, but it doesn’t always represent the easiest way to get a handle on the view controllers involved. For modal segues, the UIViewController class gives us variable properties that make it easy to reference the source and destination view controllers: presentingViewController and presentedViewController.

In other words, we can reference the original (source) view controller within a view controller that has just been displayed by accessing presentingViewController. Similarly, we can get a reference to the destination view controller from the original controller with presentedViewController. It’s as easy as that.

For example, assume that the original view controller is an instance of the class ViewController, and the destination view controller is an instance of EditorViewController.

From the EditorViewController, you can access variable properties in the original view controller with the following syntax:

(presentingViewController as ViewController).<variable property>

And within the original view controller, you can manipulate variable properties in the destination view controller with this:

(presentedViewController as EditorViewController).<variable property>

The parentheses with the class name is necessary to typecast presentingViewController/presentedViewController to the right object types. Without this notation, Xcode wouldn’t know what types of view controllers these were, and we wouldn’t be able to access their variable properties.

With this data-passing knowledge under our belts, we can go ahead and build our first multi-scene application—and there’s even a surprise—you’re going to make it work on both iPhone and iPad devices.

Using Segues

We’ve reached your favorite (I hope) part of the hour’s lesson: proving that the things we’ve learned about actually work. This tutorial demonstrates the use of a second view as an editor for information in the first view. The project shows a screen with an email address and an Edit button. When edit is clicked, a new scene is shown where the address can be changed. Dismissing the editor view updates the address in the original scene. The project is named ModalEditor.

Implementation Overview

To build the project, we start with a Single View Application iPhone template, and then add an additional view and supporting view controller class to the project. The first view contains a label that displays the current email address in use, along with an Edit button. The button initiates a segue to second controller, which shows the current address in an editable field, along with a Dismiss button. The Dismiss button updates the email label in the first view and dismisses the modal view. Although we could dismiss the view with a line of code, we’ll make use of the Exit icon and unwind segue so that you can get your hands dirty with this new iOS feature.

Setting Up the Project

Begin by creating a new single-view iPhone application named ModalEditor. Remember that we’re going to need to create additional views and view controller classes for the project, so the setup is very important. Don’t skip ahead until you’re sure you’ve done the preliminary work.

Adding the Editor View Controller Class

The view that is displayed to enable editing of the email address will be controlled by a class called EditorViewController that we add to our project. To do so, follow these steps:

1. After you’ve created the project, click the + button at the bottom-left corner of the project navigator, and then click New File.

2. When prompted, choose the iOS category and the Cocoa Touch Class icon, and then click Next.

3. On the subsequent screen, name the new class EditorViewController, and pick the UIViewController subclass, as shown in Figure 11.19. Remember, you should be building this for the iPhone, so leave the device drop-down alone.

Image

FIGURE 11.19 Create a new subclass of UIViewController.

4. Click Next to continue.

5. On the final setup screen, pick the folder that contains your code files as the save location, choose your main project code group from the Group pop-up menu, and then click Create.

The new class will be added to your project. You now need to create an instance of it in the Main.storyboard file.

Adding the New Scene and Associating the View Controller

Open the Main.storyboard file in the IB editor. Display the Object Library (Control-Option-Command-3) and drag a new instance of a view controller into an empty area of the IB editor. Your display should now resemble Figure 11.20. I’ve set a simulated size for my new scene’s view controller (makes screenshots easier), but you don’t need to do that just yet.

Image

FIGURE 11.20 Add a new view controller to the project.

To associate the new view controller with the EditorViewController class you added to the project, select the View Controller icon in the second scene within the document outline, and then open the Identity Inspector (Option-Command-3). Use the Custom Class drop-down menu to select EditorViewController, as shown in Figure 11.21.

Image

FIGURE 11.21 Associate the view controller in Interface Builder with the EditorViewController class.

After making the association, you’ll notice that the document outline area updates to show one scene named View Controller Scene and another named Editor View Controller Scene. How about we change those into something a bit more friendly?

Select the view controller line for the first scene and make sure the Identity Inspector is still onscreen. Within the Document section, set the label for the first view controller to Initial. Repeat this for the second scene, changing its view controller label to Editor. The document outline will now display Initial Scene and Editor Scene, as shown in Figure 11.22. If nothing else, this is easier to type.

Image

FIGURE 11.22 Set view controller labels to create friendly scene names.

Now the structure for the application is in place, let’s think a bit about the connections we’re going to need in the implementation.

Planning the Variables and Connections

This application, as I’m sure you’ve gathered, is being written to demonstrate an iOS feature, not to do anything fancy (like hopping bunnies). The initial scene will have a label that contains that current email address. We will create a variable property to reference this called emailLabel. It will also have a button to trigger a modal segue, but we don’t need to define any outlets or actions for that.

The editor scene will have a field that will be referenced via a variable property named emailField. To ensure that the onscreen keyboard’s Done button isn’t ignored when the user finishes typing, we’ll add an action, hideKeyboard, that is connected to emailField's Did End on Exit event.

Clicking a button in the scene will update the email label in the initial scene, by way of an action called updateEditor. This button will also serve double duty and trigger an unwind segue by connecting to the Exit icon in the initial scene.

A label, a field, and a button—those are the only objects that we need to connect to code in this project.

Preparing the View Controller for an Exit

To use the storyboard Exit feature, we must add an action in the view controller that we want to exit/unwind to. In this case, it’s the ViewController class. We’ll name this action exitToHere and we’ll have to create it manually, rather than with drag and drop.

Enter the method shown in Listing 11.4 in ViewController.swift.

LISTING 11.4 Add a Method as a Placeholder for the Unwind Segue


@IBAction func exitToHere(sender: UIStoryboardSegue) {
    // Execute this code after unwinding.
}


Note that the method doesn’t really need to do anything; it just needs to be there! Everything is now in place to make all our connections in IB.

Designing the Interface

To create the interfaces for the initial and editor scenes, open the Main.storyboard file and focus on creating the initial scene. Begin by selecting the initial scene’s View Controller line and using the Attributes Inspector (Option-Command-4) to set it to a reasonable simulated iPhone size. This isn’t absolutely necessary (especially for this project), but it can make your IB area a bit less cluttered.

We’re going to do something a bit different when building our interface this hour, so don’t just look at the figure without reading the next few steps. The basic gist of it is this: Instead of just adding our labels and buttons and things into the view and calling it a day, we’re going to position them all within a new view, and then set that view to remain centered in the scene’s existing view.

Using the Object Library, drag a new view (UIView) into the existing view of your initial scene. Size it to be around 2 inches tall and stretch it to the margins on the sides of the display. Next, drag two labels and a button so that they nest inside that view.

Set one of the labels to read Email Address: and position it near the top center of the containing view. Beneath it, place the second label, with its content set to your personal email address. Stretch the second label so that its edges come close to the margins of the containing view (just in case we encounter a long email address). Finally, place the Edit button underneath the two labels. Use the Attributes Inspector (Option-Command-4) to set the style for the text to anything you want.

Now, the tricky part. We want to set constraints for the objects in our interface. Constraints are instructions that tell our onscreen objects how to position themselves properly no matter what the screen size. This process is covered in Hour 16, “Building Responsive User Interfaces,” but today you’ll get your first taste:

1. The first constraints that we need are constraints for the “Email Address:” label, the label with the address itself, and the button. Select just these three objects (they should be nested in a view within the document outline), then choose Editor, Resolve Auto Layout Issues, Add Missing Constraints (make sure that you use the Add Missing Constraints under the Selected Views heading in the menu—it appears twice).

2. Next, select only the view you added (the view that contains the labels and button), and choose Editor, Align, Horizontal Center in Container. Repeat this, choosing Editor, Align, Vertical Center in Container the second time. This adds constraints to the view object to keep it centered.

3. Finally, to make sure that everything is where it should be, choose Editor, Resolve Auto Layout Issues, Update Frames. (Again, this option appears in the menu twice. Make sure you select it from the All Views in View Controller heading.)


Note

If the option to Update Frames is grayed out in your menu, don’t worry; that just means all your interface objects are already aligned perfectly. There’s no need to do anything else.


What you’ve done with these steps is tell the labels and button to stay exactly where they are, within the view that holds them. That view, however, has been configured to stay in the center of the scene, no matter what. The reason for all this effort will be clear in a few minutes.

Figure 11.23 shows my implementation of the initial scene.

Image

FIGURE 11.23 Create the initial scene.

Next, turn your attention to the editor scene. This scene will look very similar to the first scene, but with an empty text field (UITextField) replacing the label that held the email address. This scene also contains a button, but rather than saying Edit, it should read Save. Again, you should add these elements to a new UIView that is added to the editor scene’s existing view. Once you’ve completed the layout, follow the exact same steps as before to add some basic constraints:

1. Select just the label, field, and button, then choose Editor, Resolve Auto Layout Issues, Add Missing Constraints. (Make sure that you use the Add Missing Constraints under the Selected Views heading.)

2. Next, select only the view you added choose Editor, Align, Horizontal Center in Container. Repeat this, choosing Editor, Align, Vertical Center in Container the second time.

3. Finally, choose Editor, Resolve Auto Layout Issues, Update Frames. (Again, this option appears in the menu twice. Make sure you select it from the All Views in View Controller heading.)

My final implementation, with a background color set for the editor view, is shown in Figure 11.24.

Image

FIGURE 11.24 Create the editor scene.

With both scenes built, it’s time to start making the connections that will pull everything together. Let’s start by defining the segue.

Creating the Modal Segue

To create the segue from the initial view to the editor view, Control-drag from the Edit button to the onscreen representation of the editor in Interface Builder, or to the editor scene’s view controller line in the document outline (now labeled Editor), as shown in Figure 11.25.

Image

FIGURE 11.25 Create the modal segue.

When prompted for the storyboard segue type, choose Modal. You will see a line “Present modally segue to Editor View Controller” appear in the initial scene within the document outline. Select this line and open the Attributes Inspector (Option-Command-4) to configure the segue.

Although it is purely optional for a simple project like this, provide an identifier for the segue, such as toEditor. Next, choose the transition style, such as Partial Curl. You can also set a presentation style, but because this is (currently) running on the iPhone, you’re not going to see much difference. Figure 11.26 shows the settings for my modal segue.

Image

FIGURE 11.26 Configure the modal segue.

Unwinding Back to the Initial Scene

The storyboard has a segue configured to go from the initial scene to the editor scene, but has no way to get back. For this, we’ll add an unwind segue by Control-dragging from the Save button in the editor scene to the Exit icon in the Initial Scene. (You can target the Exit icon in either the document outline or in the dock underneath the scene layout.)

Create the connection now. When you finish dragging, you’ll be prompted to choose the method to execute when the exit finishes. There is only one option, exitToHere, so choose that, as shown in Figure 11.27.

Image

FIGURE 11.27 Choose the method to unwind to.

Notice that a new unwind segue is added to your editor scene: Unwind segue to Scene Exit Placeholder. Your application now has what it needs to transition between scenes, but we still need to make the appropriate connections from the scene’s view objects (the label, field, and button) to outlets/actions in their view controllers.

Creating and Connecting the Outlets and Actions

I know what you’re thinking: “I’ve done this a million times, I’ve only got three items to connect, what’s the big deal?” Although I have every faith you’ll make the appropriate connections, remember that you’re dealing with two distinct view controllers now.

Your outlets for ViewController should be in ViewController.swift, and your outlets and actions for EditorViewController will placed in the EditorViewController.swift file. If you’re not seeing what you should be seeing in the assistant editor, use the drop-down menus that appear to choose the file you should be editing.

Adding the Outlets

Begin by selecting the label in the initial scene that contains your email address, and then switch to the assistant editor. Control-drag from the label to just below the class line in ViewController.swift. When prompted, create a new outlet for a variable property named emailLabel. One down, one to go.

Move to the editor scene and select the UITextField. The assistant editor should update to show the EditorViewController.swift file on the right. Control-drag from the field to EditorViewController.swift, targeting a spot just below the class line. Name this outlet emailField, as shown in Figure 11.28.

Image

FIGURE 11.28 Connect the UI objects to their outlets.

Adding the Actions

There are two actions to add. With the assistant editor still active, Control-drag from the Save button in the editor scene to below the IBOutlet definition in EditorViewController.swift. When prompted, add a new action named updateEditor.

Next, select the field in the editor scene and display the Connections Inspector (Option-Command-6). Drag from the circle beside the Did End on Exit sent event to just under the previous action you added, as shown in Figure 11.29. Name the new action hideKeyboard.

Image

FIGURE 11.29 Connect the event Did End On Exit to an action hideKeyboard.

You’re done with the interface and connections. Let’s finish the implementation logic.

Implementing the Application Logic

You’re in the home stretch now. The application logic is pretty easy to understand. When the user displays the editor scene, the application should grab the content from the existing emailLabel variable property on the source view controller and place it in the editor’s emailField text field. When the user clicks Save, the application should reverse the process, updating emailLabel with the content of the emailField text field. We initiate both of these changes from the EditorViewController class where we can access the initial scene’s view controller through presentingViewController.

To set the value of emailField when the editor scene first loads, we can add the EditorViewController method viewWillAppear, as shown in Listing 11.5. We need to put it in viewWillAppear because this method is executed after the field is instantiated by the view controller (that is, it is turned into a real object) but before it shown on the screen.

LISTING 11.5 Populating the Field with the Current Email Address


override func viewWillAppear(animated: Bool) {
    emailField.text =
        (presentingViewController as ViewController).emailLabel.text

    super.viewWillAppear(animated)
}


This implementation sets the text variable property of emailField in the editor view controller to the text variable property of the emailLabel in the initial view controller. I can access the initial scene’s view controller through the current view’s presentingViewController, although I have to typecast it as a ViewController object; otherwise, it wouldn’t know about the variable properties (emailLabel) that the ViewController class makes available.

Next, we need to implement the updateEditor method to do exactly the reverse of this. Update the updateEditor method with the full implementation, shown in Listing 11.6.

LISTING 11.6 Setting the Initial Scene’s Label to the Editor Scene’s Field


@IBAction func updateEditor(sender: AnyObject) {
    (presentingViewController as ViewController).emailLabel.text =
        emailField.text
}


As you can see, this is exactly the reverse of what we did to set the default value for the field (see Listing 11.5).

Hiding the Keyboard

Finally, edit EditorViewController.swift to include the implementation of hideKeyboard. Update the method to ask the emailField to resign its first responder status, thus hiding the keyboard, as shown in Listing 11.7.

LISTING 11.7 Hiding the Keyboard When Its Done Key Is Pressed


@IBAction func hideKeyboard(sender: AnyObject) {
    emailField.resignFirstResponder()
}


That’s it. There was more setup involved in this project than there was code.

Building the Application

Run the application and give it a thorough workout (as much as you can do in an application that has two buttons and a field). The end result, which took us three actual lines of functional code, is an application that switches between scenes and exchanges data between them, as shown in Figure 11.30.

Image

FIGURE 11.30 The “final” application switch scenes and moves data between them.

Popovers, Universal Applications, and iPhones

If you were reading the previous edition of the book (you’re not, are you?), you would now have reached the point where we began a whole new project for the purpose of demonstrating the similarities between popover and modal segues. As of iOS 8, because of changes to segues and storyboards, this is no longer necessary.

Remember how I asked (nicely) for you to build the ModalEditor as an iPhone application? Well, not only are we going to change it into an iPad application, but we’re also going to make it use a popover segue.

Configuring the Popover Segue

When you add a segue to a project, it can be reconfigured at any time by selecting the segue line in the document outline or the visual representation within your storyboard. Let’s change the modal segue in the project we just built so that it is a popover segue instead.

Open the Main.storyboard file and select the “Present modally segue to Editor View Controller” segue between the Initial and Editor scenes.

Next, open the Attributes Inspector (Option+Command+4) and use the Segue drop-down to choose Present as Popover. Configure the directions to Up, Left, and Right; these are the directions the arrow on the popover can point. Your setup should look similar to Figure 11.31.

Image

FIGURE 11.31 Configure the popover to point in whichever directions you’d like.

Now, as you’ve learned, popovers have a size that either be set programmatically or by manually changing the size of one of the views in your storyboard. When you set up the views earlier, you added constraints that will automatically center our content in the views, no matter their size. For that reason, we can just programmatically set a size for the editor view within the EditorViewController.swift file. Update the viewDidLoad method to set the preferredContentSize for the editor, as shown in Listing 11.8.

LISTING 11.8 Set a Size for the Editor Popover


override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    preferredContentSize = CGSizeMake(340,160)
}


Before going any further, take a few moments to run the application on the iPhone simulator. Touch the Edit button and see what happens? If everything is going according to plan, you’ll see a simple modal transition—but no popover! That’s because popovers are adaptive, and Apple would prefer they weren’t displayed on an iPhone. They will, however, display as a popover on the iPad. Unfortunately, if you try to run the application on the iPad simulator right now, it will just run the iPhone version, enlarged. To see the application display properly on the iPad, we need to make it a universal application.

Toggling to a Universal Application

Don’t blink or you’ll miss what we’re about to do (that is, turn our iPhone app into a universal iPhone/iPad application). To do this, select the top-level project group in the project navigator (the blue document icon). Make sure that the ModalEditor target is highlighted and that General is selected at the top of the editor area.

Scroll down to the Deployment Info section, and use the Devices drop-down menu to switch from iPhone to Universal, as shown in Figure 11.32.

Image

FIGURE 11.32 Set the Devices to Universal.

And here’s the kicker: You’re done! Try running the application on the iPad simulator. It will now run and display a popover, as shown in Figure 11.33. Try running it on an iPhone and display the popover; it shows as a modal view.

Image

FIGURE 11.33 The iPad simulator now shows a popover.

The two features of iOS and Xcode that make what we’ve done here possible (in terms of making the application universal) are size classes (which let us use a single storyboard for both iPhones and iPads) and Auto Layout constraints. You’ll learn more about both of these features later in the book, but this should give you an idea of just how easy it can be to deal with all your iOS platforms in a single application.


Try it Yourself: Where’s My iPhone Popover, Already?!

As you’ve seen during our tutorial this hour, you can use a popover segue on an iPhone, but it adapts to the Apple’s typical iPhone conventions and doesn’t actually display as a popover. That’s all fine and well, but with all these huge new iPhones, what if you really do want a popover displayed? You can do it, but it takes a bit of overriding the default segue behavior. This quick exercise takes you through the steps of making a popover segue on an iPhone behave identically to an iPad.

Begin by making a copy of your final popover-enabled ModalEditor project and opening the copy in Xcode.

To make iOS display a popover on the iPhone, we must tell the popover to stop being adaptive. This is accomplished by having the view controller that will invoke the popover (ViewController) adopt the UIPopoverPresentationControllerDelegate protocol. We’ll also add one method from that protocol that disables adaptive popovers, and, finally, we’ll set the popover controller’s delegate to the ViewController.

To conform to the UIPopoverPresentationControllerDelegate, add the protocol name to the end of the class line in ViewController.swift:

class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {

Next, add the adaptivePresentationStyleForPresentationController method to ViewController.swift. This method, shown in Listing 11.9, will return the constant UIModalPresentationStyle.None stating that the segue shouldn’t try to adapt to any other style.

LISTING 11.9 Disable the Adaptive Segue


func adaptivePresentationStyleForPresentationController(controller:
    UIPresentationController) -> UIModalPresentationStyle {
        return UIModalPresentationStyle.None
}


Last but not least, the prepareForSegue method must be added to graph the popoverPresentationController and set its delegate variable property to the ViewController class (just self, since we’re writing this code in the ViewController.swift).

LISTING 11.10 Set the Popover Presentation Controller Delegate


override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    let destinationViewController:EditorViewController =
        segue.destinationViewController as EditorViewController
    destinationViewController.popoverPresentationController!.delegate=self
}


Now run the application on the iPhone Simulator and try pressing the Edit button. Your display should look pretty close to Figure 11.34.

Image

FIGURE 11.34 Popovers on iPhones, what will Apple think of next?

Note that this isn’t really a practical application of iPhone popover capability (the keyboard will cover part of the popover), but this same technique can be used in other applications to make popovers appear in your apps (regardless of the device they’re running on).


Further Exploration

Let me be clear: Storyboards and segues are new and evolving. In fact, many developers are still using the previous version of Apple’s interface technology (NIB files) in their projects. The trick with turning our application instantly into a universal app has only been possible since the release of iOS 8, because of fundamental changes to storyboards. The point is this: What works today may work entirely differently tomorrow. The chapter you just finished reading is 20 pages shorter than the previous edition because of this.

To learn more, read the View Controller Programming Guide for iOS; it will give you a good background on views, view controllers, and how they can be manipulated in code. It’s a very long guide, so you may want to jump around through the sections that interest you the most. The View Controller Catalog for iOS is another great reference and walks you through the different view controller types (such as the modal controllers and popovers you’ve used this hour).

Summary

This hour’s lesson was, yes, I know, longer than an hour. The topics that it introduced—multiple scenes and segues—are very important aspects of iOS development that can take your apps from being simple single-view utility-style programs to full-featured software. You learned how to visually and programmatically create modal segues, handle interactions between scenes, and unwind to previous scenes via the storyboard exit. We also explored the popover UI element and how it can be created and displayed from a segue or via code.

Something to keep in the back of your mind while you develop is that while visually created segues are great, and handle many different situations, they might not always be the best approach. Programmatically switching between views gives us a flexibility that we don’t have with preset segues in IB. If you find yourself struggling to make something work in IB, consider doing it through code.

Q&A

Q. Why doesn’t iOS just provide windows?

A. Can you imagine managing windows with just your fingers? The iOS interface is designed to be touched. It is not meant to model a typical desktop application environment, which was built around the mouse.

Q. Should I use nonadaptive popovers on the iPhone?

A. If the popover fits the UI, absolutely! Apple’s latest iPhones have lots of screen real estate, and popovers work just fine. However, if your popover is going to take up the whole iPhone screen, it really doesn’t really add any usability by being a popover, does it?

Workshop

Quiz

1. In iOS 8, segues that change depending on the device you are running on are called what?

a. Adaptive

b. Conforming

c. Device agnostic

d. Modal

2. Popovers are a type of what kind of segue?

a. Unwind

b. Modal

c. Presentation

d. Navigation

3. In a typical multiscene application, unique scenes will have unique __________.

a. Purposes

b. Labels

c. Colors

d. View controllers

4. A form sheet is an example of a modal segue’s what?

a. Style mode

b. Presentation type

c. Presentation style

d. Transition type

5. What method is used to display a scene programmatically?

a. presentViewController

b. showViewController

c. displayViewController

d. useViewController

6. To remove a view from being displayed, you could use which method?

a. hideViewControllerAnimated

b. clearViewControllerAnimated

c. removeViewControllerAnimated

d. dismissViewControllerAnimated

7. The process of moving back to an earlier scene is called what?

a. Winding

b. Unwinding

c. Exiting

d. Switching

8. Which variable property, set within a view controller, determines the size of the view when presented as a popover?

a. setContentSize

b. forcedContentSize

c. preferredContentSize

d. desiredContentSize

9. Which method is executed prior to a segue, giving developers an opportunity to configure or modify the segue’s behavior?

a. prepareForSegue

b. segueStart

c. segueBegin

d. prepareToSegue

10. To access the parent view controller from the current view controller, you could use which variable property?

a. startViewController

b. oldViewController

c. presentingViewController

d. topViewController

Answers

1. A. Adaptive segues enable you to create one segue and use it across all your devices.

2. B. Popovers are a special type of modal segue that include a UIPopoverPresentationController.

3. D. Unique scenes usually have unique view controller classes to handle their display and operation.

4. C. A form sheet is an example of a presentation style.

5. A. The presentViewController method is used to display a scene’s view controller programmatically.

6. D. Use the dismissViewControllerAnimated method to remove a view from the device’s display.

7. B. The process of moving back to an earlier scene by way of an exit segue is called unwinding.

8. C. Setting the preferredContentSize for view controller will determine its size when displayed in a popover.

9. A. The prepareForSegue method is called as a segue begins, giving developers a chance to intercept and configure segue parameters before the display changes.

10. C. Use the presentingViewController method to access the controller that displayed another.

Activities

1. Return to a project in an earlier hour and implement a “configuration” interface by way of a segue.

2. Update the tutorials in this lesson to programmatically create and display a scene.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset