Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2011-102
$eventId
ID of event: wwdc2011
$eventContentId
ID of session without event part: 102
$eventShortId
Shortened ID of event: wwdc11
$year
Year of session: 2011
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2011] [Session 102] Implementin...

WWDC11 • Session 102

Implementing UIViewController Containment

App Frameworks • iOS • 58:42

View controllers are a fundamental piece of any iOS application. Come to this session to learn how to ensure child view controllers receive appearance and rotation callbacks correctly, new methods of controlling view controller presentation, and become acquainted with a new view controller container class.

Speakers: Matt Gamble, Bruce Nilo

Unlisted on Apple Developer site

Downloads from Apple

HD Video (439.4 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

So first some context. View controllers are a centerpiece object of UIKit. They were introduced in the very first SDK, and since then we've been incrementally augmenting them, adding new features, making them better than ever. And in iOS 5, we're continuing that tradition, and today we're going to talk about it.

So we have a few goals for this talk. We want to talk ultimately about what view controller containers are. And when you leave this talk today, you should intimately know the difference between a regular content controller and a container controller. Most of you probably already do. Split view controllers, navigation controllers versus the controllers you create to display your own data. You're going to know how, and more importantly, when to implement a custom UIViewController container.

My colleague Matt Gamble is going to introduce a brand new container controller that we've introduced on iOS 5 called the UI Page View Controller. It has a really great page curl effect that you guys are going to love to include in your applications. Finally, we're going to share some tips and talk about new API.

So before we actually get to a quick review, I'm kind of curious. How many people in the audience, just a quick show of hands, have not used view controllers in their applications before? Okay, so we got an audience full of veterans. Okay, that's good. Well, we're still gonna go through the review. But we're gonna do it from the point of view of trying to set the stage for what view controller containment is all about.

So the first question that I'm sure all of you know the answer to is, why do I want to use a view controller anyway? And there's really two quick and good answers. We developed view controllers at Apple because we realized there was a common pattern in many of the applications that we were developing and delivering to our customers. And we abstracted that and made it available to our third-party developers as a UI view controller and their related subclasses. Using view controllers, you guys can make high-quality applications that have the look and feel of iOS applications that we all know and love.

Secondly, they're fundamentally reusable. They're designed in a way that kind of encapsulates the data and the view and everything in one nice bundle that you can take and reuse in different parts of your application. In short, you get to write less code, focus on the code you really care about, and have it look great.

Okay, let's talk about what a view controller is. At the end of the day, it's just a controller. I'm sure everyone in this audience, or mostly everyone in this audience, is familiar with the model view controller pattern that pervades COCA. Well, a view controller is just a controller. Forget about the view, it's just a controller.

It mediates the data that you store in your model objects with the views that it presents on the screen. And these views are complex. It's not a single view that a view controller manages. It's an entire hierarchy of views. And in fact, we have documented in the past, and we still do, I believe, that you should consider them as managing an entire screen full of content. They're somewhat heavyweight objects that you want to reuse over and over again.

They're often packaged with their model object. In fact, We deliver in other frameworks on iOS a whole number of view controllers that you can present from anywhere in your application and it just works. So, for example, the new Tweet Compose View Controller that I believe was demoed in some of the keynote presentations.

So if you know nothing else about a view controller, one thing that you should know is view controllers are probably the most social object in UIKit. They love to connect with each other. In fact, their rasant detra is to connect with one another. They transition on and off the screen between themselves. They pop, they push. That's the view. That's what the view and view controller ultimately really means.

OK, I want to talk a little bit about the statement that they manage a screen full of content. In 3.2 and the iPad, all of a sudden we introduced new controller objects which seemed to contain other controller objects that contained your controller objects that are no longer full screen.

What gives? Well, the advice still holds and perhaps a more technically accurate way of thinking about it is that your view controllers should really anticipate being presented in different ways. And their view hierarchy should ultimately be flexible and adjust to it. It might appear on the left side of a split view controller or perhaps in a popover controller or perhaps even modally.

So I guess a better way of saying it is that they should be considered as managing a self-contained unit of content or presentation unit. Okay, rewind. There actually is one view controller that actually really does manage a full screen of content. And that's the root view controller. Now the root view controller, we've used the word root view controller a lot. And sometimes it can get confusing.

But The root view controller I'm talking about is the one which is a property of the window object, and it's actually a pretty important controller object. There's been some confusion, and some developers have actually taken other view controllers' views and laid them over on top of the root view controller, and not good things happen when you do that.

In particular, one of the responsibilities of the root view controller is it knows how to forward rotation events. When the device rotates, it's really the controller that knows what the presentation stack is and will forward the rotation events appropriately. Okay, so how do you use these? Basically everyone knows because nobody raised their hands. Use subclass ViewController.

You in IB or otherwise programmatically associate your view controller with a complex view hierarchy. You override select API that is documented in ViewController. You add your application logic, mix it all together, do the provisioning tango, sit back, and get five stars on the App Store. Well, I want to call out a couple of that API that you guys override for view controllers.

And I'm making a point of these specific callbacks to view controller, because these are the callbacks that the container controllers actually manage in some sense. And that's the appearance callbacks, viewWillAppear, didAppear, didDisappear, willDisappear, and the rotation callbacks. So we're gonna be talking about that a little bit more as this talk proceeds. So quick summary.

View controllers are just controllers. In fact, they manage an entire view hierarchy, not a single view. You don't necessarily need a view controller for every view in your view hierarchy. And in fact, it's perfectly reasonable to have other controller objects which are subordinate to your view controller. View controllers are all about presentation and connection with other view controllers. They're usually self-contained, meaning they're packaged with their model object. They can be put into different parts of your application.

And they really connect with each other and they support the common iOS application flows that everybody knows and is familiar with. So let's talk about where we're going to go now in this talk, all the new stuff. We're going to talk about the view controller hierarchy versus the view hierarchy. And believe me, it can get a little bit confusing. We often conflate the two hierarchies. There I go again.

We're going to talk about three ways that view controllers get themselves on and off the screen. And really, it kind of sums up all the ways they get on and off the screen. We're going to design a custom container controller. And we're going to talk about some of the new and changed API along the way. So let's get busy. View controller containers, a tale of two hierarchies.

So it's so confusing to me when I talk about this that I decided I was going to put a legend out there to keep me honest. So if I'm kind of mixing the terms up, understand that blue means view or view hierarchy, and yellow or gold means I'm talking about the controller hierarchy, or I'm trying to make an association between the two. A blue arrow is a super view sub view relationship, and a gray arrow is a parent-child view controller relationship.

So armed with that graphical notation, let's deconstruct a common application's view controller/view hierarchy. What we see here is a view hierarchy. This is what you see on the screen. The view controllers are kind of behind the scenes. They're the puppet masters that control what's actually going on in the application. So that topmost view, which is in the window, which happens to be the root view controller in this case, is associated with a split view controller.

And on the left-hand side, we have a navigation controller, which happens to be a subview of the view that's managed by the split view controller. And it has its associated yellow box. Now, the two that I just highlighted, those are content controllers. They happen to be contained within the navigation controller on the one side and the split view controller on the other side. And now you're seeing this kind of parallel hierarchy here. Those content controllers are typically what you guys create.

And up until now, we didn't really encourage anyone to create their own content, I mean, container controllers. But of course, that's what we're talking about how to do now. Now, there's an implied controller hierarchy relationship here with these gray arrows. And you'll notice that there's a box on the right side that really doesn't correlate to a view at all on the left side.

And that's because it's managed by the navigation controller. That little button on the left kind of is a proxy to get you to the view that the mailbox controller box actually manages. But it's not part of the view hierarchies. But the view controller hierarchy, it's there. So the view controller hierarchy both shadows the view hierarchy that you see, but it also has some potential view hierarchies that it's encoding that aren't there.

So the view controller hierarchy both shadows the view hierarchy that you see, but it also has some potential view hierarchies that it's encoding that aren't yet present that might be present. Okay, let's deconstruct it the other way. So we have this controller hierarchy, and we're going to show explicitly the contained relationships between the views.

I'm going to kind of motor through that. But you can see there's kind of-- I'm drawing the arrows to emphasize that there's a super view sub view kind of tree relationship here. And that tree relationship is kind of these nested views that lay out. And you'll notice that that mailbox view is kind of orphaned off to the side. It's not in the window hierarchy at all yet. But that's OK. It's still associated with a view, which may or may not even have been created yet.

So we'd like to think about this abstractly, and we have this kind of almost one-to-one relationship between the view controller hierarchy and the view hierarchy, but not quite. And the reason I like to think about it this way is because if I really thought about it, all of a sudden I'd be lost in the trees. There's no forest, there's just views everywhere and forget it.

So let's go back to the more simple way of thinking about it. So what should you know about these two hierarchies now that we've seen how they kind of relate with one another? The first thing to kind of digest is that the container controllers, the navigation controller, the split view controller, they're responsible for the child-parent relationships.

And you can see this if you look at the API that we have made that is currently published and available for existing container controllers. So for example, when I create a navigation controller, I call in it with a review controller. And what I've effectively done is I've created a parent-child relationship between those controllers when I initialized the navigation controller. Similarly, with split view controller.

When I create that, I can call set view controllers, and I've established parent-child relationships again between the left side controller and the right side controller and the containing split view controller. And more dynamically, as things are running and I'm pushing and popping view controllers, assuming that the clicker clicks, I'm also adding a child relationship, and if I pop off the navigation controller, I'm removing that child relationship.

So somehow that API is able to create those relationships. And that's what we need to enable you guys to do. So what we have here is kind of a snippet of the demo app that we're going to be showing you a little bit later. It's a relatively simple view controller hierarchy. This view hierarchy is on the side. And we want to talk about what we need to do to get you to be able to create API that adds child and parent. View controller relationships.

So first bit of API. It's actually kind of simple and obvious. You basically call add child view controllers, array of child controllers, and remove from parent view controller. Really straightforward. You can access what a view controller's children are via the child controller view controller's property. And there's some callbacks that we make available.

And I'll get a little bit, I'm going to talk a little bit more about why those callbacks are interesting. But at the very least, if you wanted to know when you got a parent controller and when you lost a parent controller, you can override those. And of course, you're going to call super, right? And get that information.

Now I want to emphasize something about the top, certainly the top two methods. These are not meant to be called by anybody. They're really provided if you are subclassing view controller and creating your own custom controller. And then you're going to provide some API. Maybe it's going to be something like a navigation controller, push or pop. And you're going to call those methods to create that child parent relationship.

I can promise you that bad things will happen if you call that bad child view controller on a controller that you didn't implement. Because they're not going to be expecting it. And all of a sudden, they're going to have children that they didn't know they had. So that can't be good.

Okay, what else should you know? There's actually consistent and inconsistent view hierarchies. And I have dealt firsthand with many of the inconsistent view hierarchies that come in reported as bugs. So let's talk about what an inconsistent view hierarchy is. Basically what this picture is showing is it's showing window hierarchy. There's one root view controller that kind of is kind of owning the show there.

And off to the side, we have this kind of disconnected view controller hierarchy with its associated views. Maybe it's a nav controller that got presented and dismissed, and we're holding a pointer to it. And then we say, you know what? I really want to grab the child, the top view controller of that nav controller, and I want to put it into my root view controller.

So I'm going to reach inside, grab its view, say add sub view, and it's good, right? No problem. Well, there's a little bit of a problem. If you kind of look at what we have here, we have a child view controller that says its parent is whatever it says there.

I can't read it down there. And if you look at the right side, its corresponding view hierarchy, and you walk up its ancestor views, you see that there is no such parent associated with any view. Well, we don't like that. And that's an inconsistent hierarchy. And if you guys are doing that in your applications, if you see this exception, that's exactly what it means. It means that a view from a view controller, let me rephrase that.

The view associated with a view controller got pulled out and added directly into the view hierarchy, and it's pointing to view controllers that aren't in that Windows view hierarchy. So why is that a bad thing? You know, maybe we should just allow that and live with it. Well, it's bad because we rely on those parent-child controller relationships to forward those callback methods that I was speaking about.

In this case, that child kind of may or may not get callbacks, which may or may not be a bad thing, and maybe your application doesn't care about, but it also can lead to other kinds of inconsistencies. If we end up now pointing to the same view controller from two different controller hierarchies, and now we want to present one on top of the other, we just didn't want to deal with all of that mess and said, okay, this is an inconsistent state.

Okay, there's one other really important thing to understand about the controller hierarchies. And that is, you should, if you're implementing a custom container controller, you really want to know when the appearance callbacks are actually made. And there's oftentimes a lot of confusion about that. So let's kind of walk through it a little bit.

I'm going to create some new API on my custom container. I call it Flip to Note. And basically, Flip to Note does just that. It adds a new note controller on top of this container or content controller, which happens to be a recipe because that's the app that we're going to be extending, swaps the views out, and all is good. So the question is, is when in this whole exchange did viewWillAppear, viewDidAppear, viewWillDisappear, viewDidDisappear get called? And what are the guarantees that we're making about that? Okay, first let's get a peek at what that code might look like.

It's actually relatively simple and we're going to talk about some of the new API that's there, but some of the API we've already spoken about, so spoken to. Add child view controller. Well, guess what? View will appear, view did appear, has nothing to do with add child view controller. All that add child view controller does is it says, this view controller is a child of that one and it has nothing to do with view appearance.

That new call in there that I'm going to talk about in a bit actually kind of hides when all of the view will appear, view did appears happen. But The main point I want you to understand is that when they get called is associated with when views move in and out of the window hierarchy.

That doesn't necessarily mean that you see it. So there's immediately there's some cause for confusion there. You could actually add a view underneath another view, you never see it and you'll get called with viewWillAppear and viewDidAppear and you'll say what gives, I don't see anything. Well now you know. I mean what it really means is is that the view has made it into the Windows view hierarchy.

What are we going to say about guarantees about all of this? Well, viewWillAppear, as I said, it's called before the view is added into the Windows view hierarchy. And it's also called before we lay out the subviews of that view controller's view. We never really specified this before, but this is something we want to guarantee now. It kind of doesn't make sense to say view will appear and have view will layout subviews kind of happening before view will appear. Same review did appear.

It's called after the views added to the window hierarchy. When after? Well, we're going to be a little bit kind of imprecise on that. It might happen after an animation completes. It might happen not after an animation completes. And actually, for custom containers, that semantic is left up to you. However, it is going to get called after layout subviews. So you got to make sure that that view controller's view has been laid out before viewed it appears call.

and view will disappear and view did disappear. Basically, they're called before the view is removed from window hierarchy and after the view is removed from the window hierarchy. You'll all be happy to know that if you kind of do the logic there, view will appear, will be called before view did appear. All right.

One thing I want to talk a little bit about here is that addChildViewController is going to call willMoveToParentViewController with self for you. We already know that's going to happen because you've made the indication that you're adding that child. On the other hand, after this whole transition occurs, in the completion handler to this method, which we're going to talk about, we make the explicit call to didMoveToParentViewController to say, hey, we're done. You've moved in now. All is good.

So let's look at that method. That method is actually kind of a helper method. There isn't a lot new there. If you guys are familiar with the UIViewAnimationBlock API, that looks a lot like that API. The difference is that there's a from view controller and a to view controller, which are two sibling children that share a common parent view controller.

We've also added a couple of courtesy API calls for you. Controllers will now get a view will layout subviews and a view did layout subviews. Oftentimes container controllers really know where their children's frames are and so forth. So you can now just set the frame of your child controllers directly in your parent controller before layout subviews is actually called.

That kind of prevents-- yeah, that's a good thing. We've gotten a lot of requests for that, and we heard you. OK, how do view controllers get on and off the screen? Well, we talked about container controllers. That's kind of what container controllers are all about. By presentation and dismissal, there's kind of, you guys are familiar with it as present modal, dismiss modal. And by direct view manipulation, and we talked about that a little bit too. And in fact, container controllers basically are stylized wrappers around direct view manipulation.

Okay, so split view controller, nav controller on the left side, push, pop. That's how view controllers, container controllers connect one with the other. So before iOS 5, we had present modal view controller, dismiss modal view controller. We're renaming that, on iOS 5, we're calling it Present View Controller Animated Completion. And hey, there's a completion handler on Present and Dismiss View Controller. Which will be called after view did appear and all of that. I think it's specified in the documentation, if it isn't. Email me and I'll tell you what it is.

We changed the name. We got rid of the modal because with current context presentations on the iPad, it's not always modal. Sometimes it's just I presented this out-of-band view controller and I can still interact with other parts of the screen. There's still a modal presentation style property, but that API has changed a bit.

So let's deconstruct it and look at what present and dismiss actually do. So this is the familiar deconstruction that I'm going to kind of fly through, because I think my time is getting short here. We set up the parent view controller relationships. What I'm really trying to get to is the call to present view controller, which will be here any moment now. Ah, there we go. So we're going to call present view controller, and we're going to call it on the bottom most leaf child controller there. So any guesses what the presenting view controller is there? If you said the table view controller, you're wrong.

And it's not the nav controller either. It actually walks all the way up to the root view controller. And that compose sheet is being presented by that root view controller. Now, there are ways to control this. When you do current context presentations, we're going to talk about some of those.

Okay, the other way to get view controllers on and off screen, direct view manipulation. So one of the things we showed in previous SDKs was window add subview, root view controller view, and bad things happened with that. We changed that to root view controller property, but we set the stage.

We said, yeah, views of view controllers are good for just grabbing and inserting into the window hierarchy. So we moved to that way, and now some of you guys may have code that does something like this. I got a view controller. I take its view. I do the add subview thing, and... I get that.

And this is actually is not an inconsistent hierarchy because there's no parent. But what I've ended up doing here is I have kind of two root view controllers now kind of going off. And it's not the best way to do this. Better is to add the child view controller relationship directly and have the parent view controller manage The direct insertion into the subview. Because a parent view controller really knows where the children should go. Again, it's a case of the children don't choose their parents. The parents kind of should call the shots here.

Okay. When do I want to create a custom view controller container? Well, the real answer is you probably don't want to. Or at least you should think twice about it before you do. We provide a lot of container controllers and we're constantly making them better and we want to make them better. We want to hear from you guys how to make them better. But sometimes there are good reasons.

Sometimes, you know, the look of our container controller isn't quite the look that you're trying to get over to your own users. Or maybe you want a custom application flow. You just want things to move a little bit differently than what you get out of the box. And finally, if your application actually is doing this direct view manipulation dance, you probably want to consider maybe inserting a container controller in there somewhere and encapsulating it that way.

So this is kind of a oblique plug for some new API. But we have split view controllers on the iPad. And one of the biggest requests we've gotten over time has been, I want my left side view controller to appear in portrait. I don't want the little pop-up button. And you might think, hey, that's a good example of when I'm going to create a custom container controller, because damn it, they don't provide that capability.

Well, that might be a good argument, except in iOS 5, you can now do that on split view controller. So that's kind of an example of why... Think twice before you create your custom containers and definitely give us feedback on the controllers that we have. Okay, I think Chris Parker in a previous talk talked a little bit about that.

So let's talk about designing a new app flow in a custom container. So Matt and I, a few weeks ago, we were... I'm trying to figure out what we should demo at WWDC. And we decided that what we wanted to do was show-- was rev the old recipes demo, but kind of make it an iPad app and highlight a new application flow.

What we see here is we see a custom bar that's owned by the topmost container view controller. And I can select things on that bar. I can bring out a browser. And then I can navigate between different recipes. And in this case, my part of the demo is just these are just pictures. And I can move these things in and out.

In this case, I don't keep a stack of them. It's just the current one is the one that's presented. There's some other things that this demo does and we're gonna go through it right now. So let's have a quick demo of a custom container, look at some code.

All right. So this is the interface definition of the CVC Flipnote View Controller. And there's a couple of things I'd like to point out in the header file. One is that this is the API that we've added. We've added this flip to note, flip from note, set content controller.

Those API methods are the API that the content controller exposes to manipulate the child parent view controller relationships. We have a lot of custom views that set up kind of the Chrome and the look of this content controller, including a toolbar and so forth. And we've implemented it in a way that we wanted it to be reusable in different contexts.

So the model object has a protocol associated with it. And if any object supports this protocol, it can use this container controller and get all the goodness that it provides. And in fact, that's exactly what Matt is going to show you. When I stop speaking. So let's run the demo in the simulator. And what you're gonna see here is you see this content controller on the outside. I can select different recipes.

I can -- what I really wanted to do is be able to flip the thing to the side, write a note about it if I wanted to, you know, something like that. Go back. Ultimately share my recipes with my friends. But, hey, what happened there? So, I kind of went a little bit quickly, but basically what happened is this isn't quite optimal here. We didn't resynchronize that table controller with the actual picture. And the reason that happened is because we got a viewWillAppear on the picture controller, but we didn't do anything about that. So we're going to change that, if I can find the viewWillAppear method.

Come on, there it is, and the view did appear method, excuse me. And there's this new API here that I'm gonna talk about once I get off this demo thing. Where when that picture controller's viewDidAppear is called, we're going to check whether or not I'm moving to a parent view controller or not. And if I am, I'm going to synchronize the selection list if I need to.

If I'm not moving into a new parent view controller, or if I am moving into a new parent view controller, I don't need to do that because I'm brand new to the scene. I'm already synchronized. I'm there because I was selected. So let's stop the demo from running. Run it again. Show the note. I don't want to do that. I need to show content. Show the note.

Go to Gendersnaps, hide the note, and now we synchronize back. So let's talk a little bit about what was going on here. Well, first of all, there's two API methods that we were doing when we were to flip to note, which we've seen before, and flip from note, which is kind of the inverse of flip to note.

These two methods are very similar to what push and pop view controller on the navigation controller method is. And there's kind of like a symmetry to them. You'll notice that in the first one, when we're popping or we're removing a controller, we call will move to parent view controller with a nil.

Because we don't know that you're actually doing that yet. However, when all is said and done in the completion method, we call remove from parent view controller. And at that point, we automatically call did move to parent view controller for you because, hey, we know you've just moved out because you've made that call. The code that I edited, we're gonna look at in a second.

But what I wanted to do is point out exactly what's going on here. When we flip the note, we've effectively added a child controller onto the stack. We've kept the content, the waffles as it were, underneath. We've swapped the views. We're hanging onto the waffle view because when we pop the thing ultimately, that waffle view is going back.

Now, is moving to parent view controllers is an interesting call. That's what made things resynchronize. I'm going to talk about it in terms of the new API here. Many of you have requested that you really want to know if a view controller is appearing because it just got pushed onto a navigation controller or because something got popped off the navigation controller and you're appearing again. And we needed to come up with a slightly general way to handle that, given that now you guys can create your own container controllers. So that's what is moving to parent view controller is actually doing there.

Because depending on how your content controller is constructed, you'll see that the patterns in the code, when you go back and look at it, because it is sample code, is such that that is going to return yes in the appearance callbacks between view will appear and view did appear if it is new to the scene.

In other words, if you've just pushed a view controller onto, you know, if you've just added a view controller onto a navigation controller, and you've just provided a view controller child to its parent and are changing the views out, that's going to return yes. And if it's already a child and you've just removed something and revealed that view controller again, it's going to return no. So it's a way that you can disambiguate whether or not a view controller is appearing because something got pushed on you or popped off you.

The other method is the exact same thing except it regards disappearing. Are you disappearing because something got pushed on you? Or because you got popped off of something? And for completion here, we've added two sets of parallel methods, exact same semantic, except they give you an indication of when a view controller is being presented over you or dismissed from you.

Hopefully that's clear. Now, I really hope this method scares you. It scares me a little bit. And I'm not even going to try to say it because I can't read it right now. We wanted to give you guys an escape hatch, as it were. If you're implementing a container controller and you don't want the automatic appearance callbacks to happen, remember, appearance callbacks happen when views get moved in and out of the window hierarchy. And we manage it all for you automatically.

You don't really have to do a lot. But sometimes, you know, that's not what you want. And you want to manage it yourself. Maybe you have some really just incredible animation and you're moving views in and out of each other and you just don't want these appearance callbacks to happen out of your control.

Well, you can override that method, whose name I can't say, and return no. And if you do that, what that means is that you're responsible for forwarding those appearance callbacks yourself. So this is kind of like idealized code there, but you could have like done it yourself, you know, using CA animation, whatever you want, and just make sure that you follow the invariants that aren't too stringent that I talked about earlier in the talk. Okay, there's one other thing I want to demo here. And then I'm gonna give it over to Matt.

Okay, well, I don't want to hit that button, because that button is Interesting. Okay, we have some technical difficulty here. I'm not gonna show that part of the demo because we didn't configure this demo machine to have email. So I'm gonna talk to it. Once I click the presentation, So imagine you saw a demo, and it was great.

You click the little share button, and in addition to the tweet, there was an email. And we were gonna present the mail compose sheet modally. And I think I have some slides that kinda talk about it. And basically the code that we're gonna go through runs something like this.

I could either be sharing from the note controller that's up there, or I could be sharing from the content controller. And in one case, I got this full screen presentation, and it covered the entire screen. In the other case, it kind of appeared nicely and nestled right in the view of the note or the content controller. And the other one looks a little bit better. So I wanted to show you how you can affect that. Now, first of all, you may be familiar with current context presentation.

Maybe? Okay. You can set the modal presentation style to be current context, and I think somewhere in that code that I can't read, we're doing that. And it's effectively we're calling present view controller in the exact same way on both the note controller and the content controller. And in one case, it goes full screen. In the other case, it doesn't. And why is that? So that's what it should have looked like, but it didn't, because we didn't configure email.

And we were going to click on email, and we were going to execute that code. And we were going to basically make the recipe browser the presenting view controller. And it was going to look just like that. Believe me. And in the other case-- Other case. It kind of looked like this.

It walked up just like we walked up in the previous talk, and the presenting view controller became the root view controller again. So how can you control that? Well, prior to iOS 5, there's lots of code that kind of was going parent view controller, parent view controller, parent view controller. Now you don't have to do that. Now you can just make a set a bit effectively, set a flag in the controller hierarchy that says you define presentation context.

And as we walk up an arbitrarily deep chain of parent-child view controller relationships, the first one that has the define presentation context set is going to be the one that we present within. So it's really easy to control where those presentations occur. So that's two new bits of API. One is define presentation context. You can also, that same controller can define the transition style. So it could be, you know, slide up, cross dissolve, flip. You can set it yourself, you know, without having to worry about the code that's actually doing the presentation. All right.

One other point I wanted to make, and I think I missed this, was that parent view controller, the semantics of it have changed a bit. Parent view controller used to return the presenting view controller, the presenting modal view controller. And because of this whole set of containment changes, that's no longer true. When you call parent view controller, if you've been modally presented or presented, parent view controller may very well return the parent view controller.

And I know there's a lot of code out there that kind of doesn't expect that. So you need to be on guard for that. And if you really need the presenting view controller, there's a new API called presenting view controller that you guys can use to get that. All right, so let's go over what we've learned.

First of all, use existing containers if you can. Give us your bugs. We'll make them better. That's what we do. It might be easier to do this if you realize is that view controllers manage complex view hierarchies, and they can, in fact, have subordinate regular old controllers. If you need to create a custom view controller, do it when you need to. Do it to define new application flows, new appearances that you want. And instead of any direct view manipulation, if your app is doing direct view manipulation like this, consider refactoring it into a custom container controller. This will help future-proof your apps, if nothing else.

The API is actually beguilingly simple, but it is a little bit subtle and you got to get the ordering right and understand the two different hierarchies. So I'm going to let Matt Gamble come on the stage. He's going to enhance that demo app that wasn't working so well for me at the end, but I have faith that he's going to make it shine. And he's going to expand a little bit on the topics that I presented.

Thank you, Bruce. I'm Matt Gamble, another member of the UIKit team at Apple, and I'd like to introduce a new controller class, new to iOS 5, called the UIPageViewController. Now the UI Page View Controller is a container controller that allows you to navigate among views with a page curl transition. And this transition can be done either programmatically or via user gestures.

Now, this is a container view controller, and it leverages the new containment API. So it manages child view controllers, which are the ones actually presenting your content. And it also presents these view controllers in a prepared application flow, which in this case is our page curl transition. So to get started, we'll start by initializing an instance of UIPageViewController. And we're going to do that with the initWithTransitionStyleNavigationOrient ationOptions method.

So for this, for the transition style, we're going to pass in page curl. Now the navigation orientation, if you are doing left to right transitions, then you would want to use horizontal. If you were going to do up and down, which would be more like the pages in a wall calendar, you'd use vertical. So pass in your navigation orientation.

And then finally, there's an options dictionary where you can pass in some different options, perhaps the most interesting of which is the spine location. Now the spine location describes the line around which these page curls occur. You can have min or max, which would be an edge spine location, in which case the page curls would be happening about a line that is on one of the edges of your content area.

So in this case, you'd be seeing one page of content at a time. You could also have a mid spine location, where the spine would be in the middle, and the pages would be turning about it in the center of the bounds. In this case, you'd be using two pages of content at a time.

So now that we've instantiated our page view controller and initialized it, the next step is to set some initial content. And so what you're going to do is just have your application set one or at most two initial view controllers on your page view controller. And you're going to do this with the set view controllers direction animated completion method. Now like Bruce was saying, this is a container controller.

So it implements the containment API, but that doesn't mean that you want to be calling add child view controller or set child view controllers or any of this new containment API directly on this class. So this is the method that you'll be using to actually pass your content to the page view controller.

So we'll start by passing in our array of view controllers. Again, if you have an edge spine location, which would be the min or max, this would just be one view controller. But if you had the center spine location, this would be the two. We're going to pass it in forward. Now we're setting our initial view controller so we don't need any animation, pass no. And again, we probably don't care about any completion block.

But this method is interesting as this is also how you would perform programmatic transitions. So now, of course, the direction becomes a little bit more interesting. And you're going to want to make sure to change yes for animated. And then perhaps pass in a completion block so that you know exactly when this animation is finished.

So that handles programmatic navigation and programmatic transitions between your content. But what's more interesting is having the user drive these transitions. And to do this, instead of having our application set these view controllers, we're going to have a data source that implements the UI PageViewController data source protocol.

And what's going to happen is that when the user makes a gesture, the page view controller is then going to ask that data source via the two required methods for the appropriate view controller or view controllers for that situation. And it's up to the data source to make sure to pass these back to the page view controller.

So that's two of the three pieces of the structure of a page view controller. The last piece is the delegate, which implements the UIPageViewControllerDelegate protocol. And this just allows you to do a little final customization in the behavior of the page view controller. So let's get right into using this and how you would use this in your applications.

So here we have our recipe controller object. This is the view controller whose responsibility it was to provide that content in the content area of the Flipnote controller. Now I'm going to skip down to the viewDidLoad method. And I'm going to start by-- oh, that's not what we wanted.

And we're going to start by initializing our instance of page view controller. We'll determine the appropriate spine location, construct our options dictionary. And in our options dictionary, we are specifying our spine location key. And then we pass these into the init with transition style navigation orientation options method. The next part is to set up the delegate and data source of the page view controller. In that case, it's going to be self, which is this recipe controller.

Now, like Bruce was saying, it's important to make sure that the bounds of these controllers are flexible, because you don't really know what your presentation context is going to be. And the page view controller feels the same way. So feel free to change the bounds of the page view controller's view to whatever makes sense in the context of your application. So I'm going to go ahead and set it to the bounds of this view.

And now I'm going to go about setting my initial view controllers, determine which view controllers I'm using, and then pass them in with the set view controllers direction animated completion. And again, we're setting the initial view controllers, so the animated flag and the completion, and even the direction, not that interesting at this point.

Now this class, this recipe controller, is itself a container controller. So it's important to make a few more calls. We're going to make sure to add the page view controller as a child view controller of this container. And then we're going to add the page view controller's view as a subview to this controller's view. And then finally, we're going to call didMoveToParent on the page view controller. All right, so let's take a look at what we have now.

So this looks very familiar. We saw this earlier. But instead of this being static content in the middle, Oh, we now have a nice interactive page curl transition. You can see the edge is tracking the touch. As I go over and let go, oh, here we actually get to some of the meat of our recipe. I can also navigate by just tapping on the edges. And back. So that's a lot better, a much better way to present our recipe.

So I'd like to point out a couple things. First of all, when I begin this transition, this gesture within the bounds of the page view controller, everything looks great. I get the animation I'm expecting. But if I go to this blue area slightly outside the bounds and begin, nothing happens.

That's disappointing. And users don't really have to be picky about where their touches are exactly starting or ending. So it's important to make sure that this behaves as they'd expect. So let's return to Xcode and go back to our recipe controller here. And I'm going to implement two methods. The first is viewDidAppear. And I'm going to take advantage of the page view controller's array of gesture recognizers that it vends. And I'm going to make sure to add those to the content area of our parent view controller. I'll do that in didAppear.

And then viewWillDisappear, I'll make sure to remove them as our view is going away. So let's build and run again and see if we see some improvement. So again, within the bounds, works great. And how about if I start slightly outside? All right, that works too. Much better.

This is particularly important if you want to embed this page view controller's view within some of your own Chrome to get that specific look that you want, but not want to have the users have to touch just within that specific bounds. So one more thing I'd like to point out in this demo application. If we are to rotate--I'm going to just use the key equivalent to rotate the simulator.

Okay, the same content, little bit bigger, dimensions are kind of changed. But wouldn't it be nice if instead of just showing this same single page of content, since we have this additional room and landscape, we could move our spine position to the middle and show two pages of content since we have this additional room? Wow.

Since we set our recipe controller as the delegate of the page view controller, we can go ahead and do that. So I'm going to start by implementing the page view controller spine location for interface orientation method. And this is an optional method for the delegate. Start by figuring out what is the spine location that I want to use for this particular orientation.

The next step is to start figuring out what view controllers I need and taking care of any calls that are specific to this orientation or this spine location. In this case, when we're doing a spine location min, which in this demo app is going to be a spine on the left-hand side, just showing the single page of content at a time, it's important to set double-sided to no.

This value gets implicitly set to yes if you use a mid-spine location. So if you're ever transitioning back to an edge spine location, and you want to go back to the default behavior of having the content on the front showing partially through the back, you'd want to make sure to set this back to no.

Now, what if we have a mid-spine location? Well, in this case, we're going to have to be passing an additional view controller. Because remember, we're now showing two pages of content at a time. So in addition to the currently selected one, we also need to figure out what is the other view controller and pass these two view controllers to the page view controller.

And finally, we're going to set those view controllers in the setViewControllers.direction.animated.com pletion method. Now, you are free to call this method as well as the double-sided method within this delegate method's implementation. Okay, so we have that all set. Let's take a look and see how this will work now.

So here's our portrait with our edge spine location. If I rotate, all right, get a nice cross fade to two pages of content at a time. If I begin my gesture here, you'll see it's now curling about the center line. So we have this nice double-sided with mid-spine location.

So let's quickly take a look at what we learned in that demo. Well, there are a few things we knew going in. We need to initialize our page view controller with a transition style, navigation orientation, and any of the options, like the spine location. We need to set our initial view controllers.

It's also how we drive programmatic navigation. And we saw that we can do user-driven-- Navigation by setting our data source and implementing the required methods. We also saw that we can customize the gesture area with the gesture recognizers and change the spine location on rotation with the delegate.

A lot of content here today. It's important to understand the difference between content and container view controllers. Also, you want to think about when to use custom view controller containers, to define your custom application flows or looks, and probably in place of any direct manipulation you were doing with views in the past. And then leverage our existing container controllers if at all possible, like the navigation controller, tab bar controller, and now the new UI page view controller. Thank you so much for coming. I hope you have a great rest of the week.