Developer Tools • iOS • 48:04
Storyboards in iOS make designing your application much faster and easier. Storyboards allow you to graphically arrange all your application's views within a single Xcode design canvas, where you can then define the logical flow and even assign transition animations. Learn how to use Storyboards to quickly go from concept to a fully functional iOS application.
Speakers: Joshua Pennington, Tony Ricciardi
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it may have transcription errors.
My name is Joshua Pennington, and I'm an engineer on the Interface Builder team. And today, we're going to talk about how you can adopt storyboards in your app. We're going to cover a couple topics today. I'm going to start out by giving you a quick overview of storyboards. Then my colleague Tony is going to come up here and talk about how you can adopt storyboards in applications that use code or ZIBS. And then I'm going to finish by talking about some great new features for storyboards in iOS 6.
Let's start with the basics. This is a storyboard. And a storyboard allows you to view your app's entire user interface in one place. And you can also view the transitions between the parts of your application. So you can very quickly get an overview of the application just by glancing at it. And there are two main concepts in a storyboard. The first concept is that of a scene. A scene is a view controller. And it can represent the entire screen in your app or just one major component area, like a split view pane and a split view controller on iPad. And you can drag in views. You can select things and resize them.
You can inspect their attributes in the inspector. So all of the normal interface builder affordances are present here. And this is where you're going to spend most of your time flushing out the UI of your application. So that's the first concept, a scene. The second concept is that of a segue. A segue defines navigation in your storyboard. Shows you how to get from point A to B. And you create a segue by picking an event source, like a button or a table view cell, and then choosing the scene that you would like to transition to.
You also choose the type of animation that you would like to use. And we have built-in support for all of the iOS animation types. And you can even create your own custom segues if there's a transition that you would like to express that's not built in. So that's the second concept. And you use these two pieces to build your application's UI.
Now, another important concept in an application is passing information around. I have this list of events. And when the user taps on one of the events, I want it to display a map view controller that shows the event. And defining this navigation in the storyboard is a breeze. We just create a segue from the cell to the scene that we want to display.
And when this segue runs, what we want to do is pass some information along so we can know what to display. We've got a method for that. Prepare for segue. And this is a method on UIViewController, and it's intended to be overridden. We'll give it a call on the source view controller, and you can write code here that will take effect whenever the segue fires. So whenever the segue runs, we'll call that method, and you can pass along any information that you need to display in the destination view controller. So let's take a look at what this looks like inside of an application. All right, so let's open that up.
Let's go into full screen mode. And here in my storyboard, I have three scenes. The first scene is a navigation controller. This is a standard UIKit object that manages a stack of view controllers that have been presented, and then also manages the transition between these scenes with a nice push animation.
It also draws the nav bar at the top that gives us a title and a back button. The second scene is a list of events. And I'm using a table view for this. And so at runtime, I have some code that looks in a database, and it makes a number of copies of this prototype cell that I've defined. We'll talk more about table views in a bit. And the last scene I have is a map view controller. And you'll notice if I zoom in here, you can zoom in on storyboards and double tap to zoom back in.
And on the left, I have a segue connecting the navigation controller to the list of events. This is a type of a segue called a relationship segue. And it simply defines the root view controller property on the navigation controller. And so this kind of just bootstraps the process. So when the navigation controller is displayed, the scene comes along with it.
The second segue connects the list of events to the map view controller. And this segue is linked up to that table view cell. So whenever it's tapped, we slide across to the map. What I'd like to do is add a second scene that's going to display information about the event. I want to display the details about it. And I'd like this segue to be triggered when the user taps on the little blue arrow on the side of it, like the phone application.
So I'm going to create a new scene. And I create a scene just by dragging a view controller from the library and dropping it on the canvas, like this. So I'm just going to give us a little bit of room here and drag out a new table view controller.
And I can create a segue by control dragging from the table view cell and choosing this scene. You can see here that it's presented a list. And there's two sections in this list. The first one says selection segue. And it has a number of segue types below that. And this is called the trigger. So this would let me create a segue that's going to be fired when a normal tap takes place on the table view cell. And we've already got one of these wired up to the event map controller. The second section says Accessory Action. And this is what's going to happen whenever the user taps on the Accessory Action area. And we want to create one of those. So I'm going to choose a new push segue. way.
So you can see that we now have a segue that's going from that table view cell to the scene that we just created. And we also still have that normal selection segue wired up to the map view controller. So let's customize this scene that we created. I'm gonna give it a title. It's gonna call it details.
And I have a table view below that. And table views come in two flavors. We have a prototype-based table view, which is where you have one or more prototype cells that you assign identifiers to. And then at runtime, you write code that asks for copies of these cells, which you then customize with the information. And this is fantastic for things like news feeds or emails, where you have a dynamic number of items that you'd like to display.
The second type of table view is called a static table view. And a static table view allows you to define the data set entirely in IB. So for things like menus where you may already know exactly how many things you'd like to display, this works out great. It also works out great if you have, you know, something like details for an event. I already know I have two rows I'd like to display. So I'm going to use a static table view for this. And I can change this table view to static by clicking on it. and in the attributes inspector, changing its content from dynamic prototypes to static cells.
I can select a cell and hit delete. I can also command click on this other cell and select both of them. Actually, it's like its parent there. Let me try that again. All right. And TableView cells have a number of built-in styles. I'm going to choose the right detail style so we can get two nice columns with information. And I'm going to select these labels on the right-- or on the left, actually-- and type in some information. to call this author name. And for the second row, this is going to display the date.
And while I'm at it, I think that the style would look better if it was set to grouped, so I'm going to change that as well. So I've got this table view controller here and it's got some information in it. But what I really want is to fill in those labels on the right with information from the event that was selected. So I've got a subclass of UI table view controller that has a property for an event model object and that has some code that will run and update these labels. So I'm going to set the table view controller's custom class to this subclass. I'm going to do that by selecting it and in the identity inspector, I'm going to change it's custom class.
So now when this controller is created, it's gonna be an instance of that subclass. So we've got this segue that hooks up to this controller, and the controller knows how to display an event. We just need to give it an event now. So we're gonna use that method that we talked about a bit ago called prepareForSegue. And prepareForSegue is going to run on that list of events whenever this segue is initiated. So we're gonna put some code there that's going to pass this event model object along. And whenever you write a prepareForSegue, implementation, you're going to look for identifiers on the segues. And the identifier is just a string. So we're going to assign one to the segue. And segues are just like any other object in IB. You can select one. and in the inspector assign attributes. So I'm going to call this show details.
And if I hop over to the subclass for the events view controller, I can implement prepare for segue. I'm gonna use the jump bar to move over to that file. And you can see that I already have an implementation of prepare for segue here that finds the event that goes along with the cell that was selected and sends that to the map. I'm gonna paste in another fragment that does the same thing but for the show detail segue.
So once again, this just looks at the list of events, finds the correct one, and sets that on a property on the destination view controller. Let's hit build and run and see what we have. Okay, so we've got a list of events, and when I tap on one of the events, a map is displayed showing the event's location. I can hit the back button and go back to the list. And if I tap on the detailed disclosure button on the right-hand side, that second segue is fired. We load the information and customize it for the event that was selected. So you can see that we were very quickly able to create a UI for our application using these two main concepts. And using that prepare for segue method as a glue to pass some information along. And this is the basis of how you'll build any application using a storyboard. So I'm going to invite Tony up, and he's going to talk about how you can mix storyboards with existing applications that are using code or ZIP files. Tony? TONY MCDONALD: Thanks, Joshua.
Good afternoon. My name is Tony Ricciardi, and I'm also an engineer on the Interface Builder team. In the app Joshua just showed you, the UI was implemented entirely within a single storyboard document. And that document served as the entry point to the application. Now I'd like to show you a few ways you can integrate storyboards into your app when you prefer to implement certain parts of your UI and code.
First, I'll show you how you can combine views from storyboards with views implemented in code. And then I'll show you a couple ways you can customize transitions between scenes in your storyboard using code. Let's start with an example. This is my game. It's called Dungeon Plunder. It's a retro role-playing game that I've implemented entirely in code using OpenGL. In this game, you explore this dungeon, and you collect treasure, and you fight monsters that you encounter along the way. And today, I'd like to add a new feature to this game that lets me browse through my character's inventory and see all the items I've collected in this dungeon.
I'd really like to implement this inventory screen using a new feature of UIKit called Collection View. A Collection View is like a table view in that it manages a collection of cells and also gives you a lot of freedom with how you can layout those cells. In this case, I'd like to use a two-dimensional grid layout like this.
In Xcode, we're making it very easy to design collection views in storyboards with Interface Builder. And so I'd like a way to implement this new inventory screen with a storyboard and then wire it up to the rest of my app without going back and reimplementing all my old UI code. So I can do that using the storyboard API.
First, there's a class method on UIStoryBoard called storyboardWithNameBundle. and that just lets me load a storyboard document at any point in code. And then I can call a method on that storyboard called instantiate initial view controller. And that gives me a copy of the initial view controller of that storyboard. The initial view controller is the entry point into the storyboard, and it's generally the root scene in your scene graph. And that view controller I get back is indistinguishable at runtime from any other view controller that I would create in code normally. Okay.
So now I'm going to show you a demo where I integrate that new feature into my app using a storyboard. OK. So this is my Xcode project. And you can see I've already added that storyboard to my project, but I haven't yet wired it up to the rest of my app. And before I do that, I just want to hit Build and Run. So let me quit the simulator. I'll just hit Build and Run so you can see what that currently does before I make any changes. I need to do a clean build.
So this is my main game screen. And you can see I'm about to fight this monster. I can also go over to my map screen, tapping on that tab. And I can see my character's location in the dungeon. And what I want to do now is add a third tab that has that new inventory screen. So let's go back to the storyboard. And I'm going to wire up this storyboard to my app. And you'll see that new tab. So in this storyboard, I have three scenes. On the left, I have my navigation controller, which controls the navigation stack.
Its root view controller is this table view controller. And that just has a cell for every item in my inventory. You can see I have a prototype cell that gets reused at runtime. And then when the user taps on that cell, this detail screen slides over, and we see some details for the item. So that's all already been implemented, and I just want to wire it up. So I'm going to go over to my app delegate file.
And now we're in application did finish launching with options. And in here, I just create the view controllers for my tabs and add them to this array of view controllers managed by the tab bar controller. So I'm gonna paste in a couple lines of code. And these lines just use the API I discussed. The first line loads the storyboard document, and the second line creates a copy of the initial view controller. Now all I have to do is add that view controller to this array, and I'll hit Build and Run. And you can see I have that third tab.
I can tap on a cell and see the details using that detail screen. So as I mentioned before, I really wanted to have this inventory screen laid out using a two-dimensional grid instead of this single column that I have here with a table view. So to do that, I'm going to go back to my project and swap out the table view with a collection view. Thank you. First thing I'll do is delete the table view controller, and I'll open the library and drag out a collection view controller.
So collection views in Interface Builder are very similar to table views. They have this notion of a prototype cell, which is this square you see up here. And I can design this one cell laying out its subviews and wire up some outgoing segues. And then I can copy that cell for every item in my collection that I want to share that same layout. In this case, I just want to add an image view to this cell. that's gonna show an image of my item. So I'll just drag out an image view and add it to the cell.
At runtime when I create copies of this cell, I need a way to reference that image view. And I can do that by creating a custom subclass of UICollectionViewCell that has an outlet to an image view. I've already done that and I'll just show you that class really quickly. So that's all we have here is a subclass of UICollectionViewCell that has an outlet to an ImageView. So now I'm gonna go back to my storyboard. I'll open up the outline so I can select the cell. And I'm going to give it that custom class.
Now I can wire up the outlet by control dragging from the cell over to the image view. I also need some code to actually go and create the copies at runtime. And that is all implemented in my custom subclass of UI Collection View Controller. Let's look at that code.
So this method here is part of the UI CollectionView data source protocol. It's called CollectionViewCellForItemAtIndexPath. And all I do in this method is create a copy of my prototype, which I reference using a reuse identifier, which I call inventory cell. And then I just set the image of that cell.
So I'm going to go back to Interface Builder and give the cell this reuse identifier so that I can refer to it at runtime. So the cell's already selected. I'll just go to the attribute inspector and call it inventory cell. Thank you. I'm also going to need to give this collection view controller a custom subclass so that that data source method gets called.
Now I want to add a header view to this collection view that shows up above each section of items and just says what kind of items are in that section, like weapons, armor, potions. And I'm going to do that the same way I designed the cell. So in Interface Builder, we also have the notion of a prototype section header view for collection views that use a flow layout, which gives you that two-dimensional grid. So I can select the collection view and go to the attributes inspector and give it a section header. I'm just going to add a label to that header view.
I'll give it some white text so we can see it, and I'll make it a little bigger. And now I'm gonna do the same thing I did for this cell. I have a custom subclass. UI collection reusable view, which just has an outlet to a label. And I'm going to go and set that as the custom class of my header view.
Now I can control drag from the header view over to the label and wire up that outlet. If we take another look at my data source, my collection view controller, you'll see I have this other method here. So I'll go back and give that reuse identifier to the header view. Now I need to wire up some segues. I want to make this collection view controller the root view controller of my navigation controller. So I'll drag out a relationship segue.
And you can see when I do that, I get a nav bar, which I can give a title. I'll call it inventory. I also want to make a push segue from the cell to the detail screen so that when the user taps on the cell, they see those details. So I'll select the cell and drag out a push segue.
So when this detail screen slides over, when that segue gets fired, I need to pass along some data. To do that, I can override prepare for segue like Josh just showed you. I've already done that. And let's take a look at that method. You can see in here the first thing I do is check the identifier of the Segway. Even though I only have one outgoing Segway for this view controller, it's still always good practice to check that identifier. Because later on down the line, I could add a second Segway and I only want this code to get executed for this particular Segway. In this code, all I do is set the title and image and the attributes that's gonna show up in that detail screen. So I need to go back and give this identifier to that segue. I'll just select the segue and call it item detail.
Okay, now I'll hit build and run. And let's take another look at the inventory screen. You can see now I've swapped out the table view for the collection view, but I still have all the same data show up. And I can tap on a cell and see the details for that item.
There's just one more thing I'd like to add to this inventory screen. I'd really like a way to know where I found this item in the dungeon. Down the line, I might be running low on potions, and I need to find some more. And it might be useful to know where I found this potion so I can go look in the same area. So I'd like a button that shows up on this screen that I can tap, and it'll take me back over to this map screen and show me where I found that item. So let's go add that.
I mentioned earlier that that map view was implemented in code. So I need a way to wire up a segue from my detail screen over to that map view controller, while having it load its view from code rather than from the storyboard. Well, it's actually very easy to do that. If I set the custom class of a view controller in my storyboard, and that custom class overrides load view, then at runtime when I reach that scene, I'm gonna execute that load view method, which loads the view from code.
So I just have to set a custom class on a view controller. I'm going to add that map view controller now. And while I'm at it, I'm going to add the tab bar controller and the game view controller that I created in code previously. And that'll let me visualize the entire flow of my application in this storyboard while still loading those views from code.
So let me zoom out a little bit. I'll move these down, make some room. And I'll drag out a tab bar controller. And this is going to represent the main tab bar controller of my application. So I'm going to make it the initial view controller. This first scene will represent the game view controller. This will represent the map view controller. And I'm going to wire up a third relationship segue here for the inventory view controller.
So let's zoom in on the GameViewController. As I mentioned, I already override load view in my GameViewController class. So I just need to set the custom class of this ViewController. And I can just delete this view, since it won't be loaded from the storyboard anyway. So now what we have here is a scene with a view controller, but no view in the storyboard. I'm also gonna customize its tab bar item. I'll give it an image. There we go. And I'll do the same thing for the map view controller. Delete its root view, and give it a custom class. And I'll customize its tab bar item.
Now I want to add that button from this detail screen over to my map view controller. Let's zoom in on the detail screen and I'll add a button and I'll call it location found. I'll wire up a segue from the button over here, make it a push segue, and I'll rearrange these scenes a little bit.
So now I need to go back and delete that code that previously created the tab bar controller and those two other view controllers, and then load the tab bar controller from the storyboard instead. So let's go back to the app delegate file. Thank you. I'm just going to select all this code and delete it. Then paste in two lines. The first one loads the storyboard and the second one sets the tab bar controller as the initial view controller of the storyboard. I'm going to hit build and run now.
And you can see I have the same functionality I had before, but now these view controllers are being loaded from the storyboard instead of using that code I had previously. So you can see my map screen that shows me my character's location, and I can tap on an item and reuse that same scene in the storyboard, create a separate copy using that segue. And now this shows -- now using that to prepare for segue method on my detail view controller, I passed along the location of the item.
So in that example, I showed you how I could combine views. I could integrate this storyboard, this new feature for the storyboard, into my app while still using my views that I implemented in code. And I could also load those code-based views from the storyboard, which let me visualize the entire flow of my application without re-implementing the UI for those old features. Now I'm going to show you a few ways you can use code to customize transitions between scenes.
Let's say I wanted to add a game over screen to my app. I wanted to present this view when my character's life total went down to zero. Normally, you would create a segue by dragging out a connection from the triggering UI element, like a button, over to the destination scene. But in this case, there's no UI element that's going to trigger the segue. I want it triggered by custom logic, when I know that my character's life total goes down to zero. So I need to create what we call a manual segue, and I do that by dragging out from the view controller's icon in the dock over to the destination scene. And then in code, at the appropriate time, I can trigger the segue by calling a method on UIViewController called performSegueWithIdentifier. And that identifier is just a string constant. I give the segue an interface builder.
Now let's say that you have a scene in your storyboard that represents a error handling view, and you want to present this whenever there's a problem communicating with the server. Your app might have 300 different places where you talk to the server, and you need a way to present this screen from an arbitrary line of code where you might not have a reference to a view controller and be able to call perform segue with identifier. So you need a way to jump to this scene without a segue. Okay. You can do that by giving the view controller an identifier in the storyboard, and then calling a method on UI storyboard called instantiate view controller with identifier. And that just lets you hop to any scene in your graph without using a segue.
So before Josh comes back up here, I just want to recap a few of the techniques I showed you for integrating storyboards into your app while implementing custom behavior and code. First, you can mix views from storyboards with views from code, either by loading a storyboard from code or by having your view controllers in your storyboard load their views from code.
I also showed you a couple ways you can customize transitions, either by triggering segues manually using perform segue with identifier, or by jumping directly to scenes using instantiate view controller with identifier. Now Josh is going to come back up here and talk about some cool new features we're adding to storyboards in iOS 6. Josh.
Thanks, Tony. Thank you, Tony. So, let's talk about some of the new features in iOS 6 for storyboards. We've got a couple new ways that you can use storyboards in your apps. And let's talk about view controllers. So view controllers are an essential part of any app, and they're also that first important concept, scenes in a storyboard.
And they're sometimes used in isolation. You might have one for an entire screen worth of content. And you'll use something like a navigation controller or a tab bar controller to manage the display of them. However, sometimes you want to display a view controller inside of a view controller. So if you wanted to do this in some applications, you might use it for something like you've got Chrome around the edge of a navigation controller. So you can use ViewController containment APIs added in iOS 5 to achieve this. If you wanted to do this today, you would assign an identifier to a scene. You'd write a bunch of code to make a copy of it and use the containment APIs to install it inside of another view controller.
But you have to write a lot of code for this, and you don't get to position the view in Interface Builder. So today, with iOS 6, you can create embed segues. You just drop in a container view and wire up an embed segue. And when your view controller loads, you automatically have another view controller inside of it. And that's it. There's no code for this. Thanks.
I'm pretty excited about this too. So let's hop over and take a look at this. And I've got this app I wrote earlier for looking at information about the gross domestic product. I'm an economics nerd, so I like this stuff. And I've got three scenes in my storyboard. I've got a nav controller.
You guys all know about that. I've got a list of states. And on the right-hand side, I've got a detail view controller. This is a pretty standard master detail app. What I'd like to do is have a map on that very last scene. But I have this map view controller that I always use in my projects because it knows how to do stuff like display a highlight region and display annotations and a bunch of other complex stuff that I don't want to duplicate in every single view controller. And I want to use this view controller inside of that other one. So I'm going to use the new embed segue to take care of that. So I'm going to start out by dragging out a container view. And a container view is one half of the equation for embed segues. So let's start by doing that. Going to zoom in and drag out a container view.
I'm going to just drop that here. And the container view automatically comes with the view controller wired up with an embed segue. And you can wire up a container view to any scene you have in your view controller. It just starts out with one. And one of the cool things about container views is that when I resize it, the scene that's attached resizes as well. So you can always see exactly what you're going to get at runtime. I'm going to make this a little bit taller. All right. And like I said, I have this subclass of UIViewController that knows all about maps. So I want to assign that as the custom class of this view controller that we're embedding. So I'm going to select that view controller and set its custom class.
And let's take a look at that subclass I'm talking about. So I've got a pretty straightforward class here. I've got two properties. I've got an outlet to a map view, so we can wire up a map view. And I've got another property that specifies the highlight region. And this just takes an object that conforms to a protocol that has some basic points to outline a shape. So I'm gonna go back to Interface Builder and add a map view, and we'll wire that up. So let's hop back over to the storyboard using the jump bar. And I'm going to drag in a map view.
I'm going to hook up that map view outlet. And so now we've got a view controller that, if I hit build and run, would be embedded inside of that container view controller. What I'd like to do is pass that highlight region along. So I'm going to give that segue an identifier, and then implement prepare for segue on the detail scene so I can pass that information along. So I'm going to click on the segue, and type in embed map controller, and hop over to the subclass for the detail view controller, and paste in a bit of code that I wrote.
And what this does is it looks for the identifier, and it passes along the detail item that I'm inspecting as the highlight region. And so this is just a model object that represents the state and it conforms to that protocol. So I'm gonna hit build and run and we can take a look at this in action.
So you can see that I have a list of states, and when I tap on one, the map view controller is installed and displays the highlight region. So we're able to very quickly have a view controller inside of another view controller and not have to write a single line of code except for that for customizing it. So I'm gonna hop back over to the slides.
So you start out by creating a container view for this. You create an embed segue, and then use prepare for segue if you need to. And just for a note on timing, whenever your view controller is loaded, by the time it's viewed and load method is called, any embed segues will have fired. So if you need to do any customization there, you'll have access. So those are embed segues, and we think that this is going to be a great new way for you to build applications. Let's talk a bit about navigation and storyboards. So right now, segues only go to brand new instances. So if a segue fires, we make a copy of the destination and we transition to it. And if you wanted to go back to a previously presented controller, this is a fully manual process. So what we usually observed is people would create a delegate method or a delegate protocol, and then they would wire up a back reference to the source view controller whenever they presented another scene for segue. And then they would implement conformance on the source view controller. And in reaction to something occurring in the presented scene, they would call the delegate methods and pass back any state. And then finally, the delegate would trigger navigation. So this is a great design pattern. There's many uses for this. And it's a pretty standard part of any Cocoa or Cocoa Touch app. But for the purpose of navigation, we wanted to abstract this away and provide an automatic mechanism to do this. So we created something called Unwind Segways.
I've got this application here, and it has a couple scenes that the user can navigate through to create an account. And when they're done, they have the option to hit Done and dismiss the form sheet, or hit Reset and go back to the beginning of the sheet to reenter in their account details. In my storyboard, it looks like this. I've got a scene that presents a navigation controller and a form sheet.
We step to those sheets, and then at the very end, I've got the buttons. What I want to do is just say, for the done button, go back to this controller. And for reset, go back to this one. If I create normal segues, it's going to make brand new copies of this. So I need some way to target existing controllers.
And we want this to work with view controllers that you've created in code or zip files. Lots of you have existing applications, and we want this to work with that. We also want this to work with third-party libraries. So we need some way to target view controllers that are not inside the storyboard. So to do this, we're going to decide the destination of the segue at runtime.
And so we do this by adding unwind actions, which are a new type of IB action to your view controller subclasses. And these serve the purpose of declaring points of interest for you to roll back to in your application. So you'd add an unwind action like done or reset to your view controller subclasses. And then we display these as destinations in Xcode when you go to create a segue. We also use these at runtime to find the destination.
and we basically just walk up the chain of controllers that have been presented until we find a controller that implements the specified unwind action. So in Xcode, after you've created an unwind action, you would just drag from a button to a new piece of UI in the dock called the exit icon. And some of you may have seen this already in the Xcode 4.5 seed.
And whenever you connect to that, we'll display a list of unwind actions. So in the case of reset, I would connect to that and choose reset. So now we have an unwind segue. And when that unwind segue fires, the first thing that we're going to do is find the destination. So we'll walk up the chain of presented items until we find a match.
at which point we'll call prepare for segue in the source. So in the case of the example, the confirmation view controller will receive prepare for segue. Then the destination's unwind action will be ran, so it gets a chance to prepare for the segue. And then we actually trigger the navigation. So in the case of a modal view controller, we'd call dismissModalViewController, and it would go away. So let's talk a bit about the search order. There's a little bit to it besides just walking up the chain. So when the reset button fires, we're going to start by asking the source view controller if it would like to handle the unwind action. And we have a new method on UIViewController called canPerformUnwindSegwayAction. And by default, this does the right thing. So it just looks at the receiver and checks to see if it has implemented the method.
So in this case, if it had a method called reset, this would return yes, and we'd declare it as the destination. If you're doing something special, like if you have a social network app that has three view controllers that all have the same unwind action and you've presented them in a row, you can use the information that we supply in this method to disambiguate and return the appropriate result. But for the primary case, you don't have to do anything here. So in the case of the confirmation sheet, it doesn't implement reset. So we know that this is not the destination. At this point, we're going to step up to the parent view controller. That's the navigation controller in this app. And it has a responsibility to search through its presented controllers to find a match for the unwind action. There's a method on ViewController for this. And if you're using the built-in UIKit containers, like UINavigationController, you don't have to do anything here, it just does the right thing. If you are creating a custom container that uses the ViewController containment APIs, you'll want to override this and search your child view controllers until you find a match.
So, navigation controller is going to search the controllers that it's presented. It checks the next controller, which doesn't implement reset, so it returns no. We then try the next one, which has a method called reset. So we're going to pick this as the destination. So at this point, we need to actually get an object to perform the navigation.
If you're using the built-in kit provided controllers, this method's already implemented, so you don't have to think about it. If you're creating a custom container, you'll want to override this to return an object that will perform the appropriate navigation. So whatever type of transition is appropriate for your custom container will be taken care of here.
So the navigation controller chooses to return an object that we'll call popToViewControllerAnimated. And at this point, we'll call prepareForSegue on the sourceViewController so it can fix up any state. We then call the unwind action on the destination so it can customize. And then we perform the navigation, which causes, in this case, Pop the View Controller to be called.
We do a similar search for the done unwind action whenever that happens, except that we'd go one more hop up the chain until we found a match. So that's the theory. Let's go look in the app and see how it actually happens. Okay, so I've got a project here. Here we go.
And not that one. Not that one. This one. OK. So it's that example app I was talking about where you create an account. And I have ViewController subclasses for the places that we'd like to unwind back to. And at the very end, I have those two buttons, Done and Reset. So we're going to go add unwind actions to the ViewController subclasses and then create segues that target those unwind actions. So I'm going to go to the reset controller and paste in a bit of code.
With unwind actions, there's just two pieces that we care about. We care that their return type is IB action and that the argument is typed UI storyboard segue. We look for these in Xcode to add them to the list. And whenever your unwind action fires, you can do whatever you want in there. You can pull information back from the segue because you have access to the source or the place that you're unwinding from. And you can also fix up any state on the controller. In the case of reset, I'm going to reset some fields that the user has entered in so they can start over again. So let's add another unwind action to the very first controller. This is what's going to happen when the done action fires. All right.
And we do a little bit more here. What we do is we access the destination view controller of the source view controller. And that is the confirmation sheet. And when I wrote this app, I made a property on the confirmation sheet that wraps up the account information that the user's entered in. So I'm just going to pull that back and use it in the app. And I also update UI to show a success view so the user gets a bit of feedback. So we have these unwind actions, so we can find places to unwind to at runtime. So let's go back to the storyboard and add unwind segues that target these actions. I'm going to go back over here.
Go to the storyboard. And I can create the unwind segue by control dragging to the exit icon. And you can see that it's populated that list with the unwind actions that we created earlier. So I'm going to choose reset for this one. Then I'm going to do the same for the done unwind action.
So now, when I hit build and run, we can take a look and see what we get. So I've got this app here and when I hit add an account, I can step through the sheet here and fill out the information. And when I hit reset, we slide back to that first controller. So it walked up the chain of controllers until it found something that implemented a reset, and then we ran the reset action, and it reset any information that was present. So let's go back and do the same thing for the done action.
So you can see that we popped back to the very first thing. Its code ran and updated the UI and pulled back the information. And it also automatically triggered the navigation. So you can see that we're able to very quickly define reverse navigation in the storyboard by adding unwind actions and then creating segues that target these actions. And then you also have new API that you can implement if you have container view controllers. So those are unwind segues. If you'd like more information, you can contact He's our developer tools evangelist. You can also post on the developer forums, and we check those. And with that, thank you.