Essentials • iOS • 54:23
View controllers are a key part of an iOS app's infrastructure. Learn how best to take advantage of these versatile objects by examining what problems they were invented to address, how they've matured over the past releases, and how to be best prepared for where they're going next.
Speakers: Matt Gamble, Bruce Nilo
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good afternoon. Welcome to the Evolution of View Controllers on iOS. I'm Matt Gamble, member of the UI kit team here at Apple. I'll be joined on stage later by my colleague, Bruce Nilo. Now, today we're going to be talking a little bit about why we use view controllers, how we can use them most effectively in our applications. And then later, Bruce is going to talk about some of the changes that we've had in iOS 6 and how to get your apps ready for a lot of the changes as we move forward.
So, view controllers. Why do we want to use UI View Controller? Well, view controllers make common tasks simpler. Now, first of all, as you could probably guess from the name, view controllers manage a view. Well, actually, more specifically, they manage a view hierarchy that's rooted at a view. And this could be a view hierarchy that you compose in code yourself, or it could be one that you design in Interface Builder. In either case, UIViewController takes care of loading the view when it's necessary automatically, even from a nib.
In addition, there's also some appearance calls that UI View Controller takes care of to tell you when your view is moving in and out of the view hierarchy. And as Bruce will show you later, there's actually some interesting things that you can do with these calls if you're designing your own custom container.
Auto rotation. This is another benefit of UI View Controller. And this can be as simple as setting your auto resizing masks correctly or taking advantage of the new Auto Layout system. Or you can actually make use of some callbacks in the View Controller API, such as will rotate to interface orientation, which is telling you when this rotation is beginning.
And then will animate rotation to interface orientation. And this is where if you wanted to do some interesting animations as part of this rotation, in your own View Controller, you could take care of this here. And then finally did rotate to interface orientation when the rotation event has completed.
UI View Controller also centralizes responsibility. I'd like to illustrate this with an example. So let's imagine we have a view hierarchy with a common goal, maybe taking some input from the user or presenting some content from somewhere. And for everything to work together, there's a bunch of messages being passed as different things are updating their state and changing other state. And then maybe we throw in a model object we got from somewhere, and then, of course, that guy has to talk to everybody else. Everybody's talking with each other, and this quickly becomes infeasible and a nightmare to maintain.
Well, UI View Controller is a great place to centralize this responsibility so that it manages the content from the model and updating the view as is appropriate. Now, if this diagram looks pretty familiar -- this is actually because it should -- this is a pattern, the MVC, Model View Controller pattern, that you've probably heard of. And so the View Controller acts as the controller in this pattern, mediating between the model and the view.
So managing a view hierarchy, centralizing responsibility, it's also a very reusable class. Now let's imagine we have our interface that we've designed, perhaps an interface builder like here. We could just present this view as in our application just as is. That's great. Or we could use this as the view controller class that we vend to a page view controller with its data source methods. We're reusing this, changing the content as makes sense for our application.
Maybe we have a universal application. We can reuse this same ViewController class and show its content in a popover controller instead. Or maybe we need to design our own custom application flow, and we've elected to use the new containment API from Introducing 5.0, and we can use it showing it on screen with some other view controllers, whatever makes the most sense for our application flow.
Also, you can take advantage of a lot of the container controllers that the system provides that take care of common workflows. Just like the navigation controller or the tab bar controller, and there's many others. And your clients are used to these. They've used them in lots of applications, and they'll be able to get up to speed very quickly. There's also some view controllers that we vend that you could then present in your application, such as this Tweet Compose View Controller and many others. And for this reason, they make a nice size block to pass around, and that's something you want to be considering.
So hopefully I've convinced you that it's a good idea to make use of view controllers. They can really help you. And so now let's talk a little bit about how to use view controllers in your applications most effectively. So to begin with, the typical application will have one window, and this one window will have one root view controller.
And you would establish this relationship probably in one of the application did or will finish launching methods by passing it to the window with the set root view controller method. So this establishes this relationship with the window. And then, when we want to be building our view controller hierarchy to describe our application flow, there's generally three main paths that we'll be using.
Now, the first of these paths is with the system-provided containers, such as the Navigation Controller and Tab Bar Controller, and there's many others like the Split View Controller and the Page View Controller. And like I mentioned, these are commonly used in applications on iOS, so users are already familiar with them. They know how to use them. They're ready to go. They'll be familiar with your app before they've even used it. So it's a great idea to use these and take advantage of them whenever it makes sense for your application.
Now, the second path is presentation. Presentation can be a great way to present content that exists outside of your standard application flow. Perhaps it's some modal content, like maybe a login or some other idea like this. And so you can simply present this content over top of your other view controllers. And since you're using the presentation mechanics, all of your rotation and all of the standard view controller mechanisms that you expect will work correctly.
And finally, creating a custom container. If you have an application flow that is not provided by one of our system containers, or if perhaps you want to use transitions between your content that we don't provide, you can do it yourself with a custom container controller, taking advantage of the containment API that was introduced in iOS 5.
I'd like to go into a little bit more detail as to how you would do this. So let's say we have our parent view controller with its view hierarchy rooted at its view, and we want to add a child view controller. Well, we'd begin by calling the addChildViewController method on the parent view controller, passing in the child. This establishes the view controller relationship, parent-child.
Then we go ahead and add the root view of this child view controller's view hierarchy wherever it makes sense in our application, in our view hierarchy, with add subview. And then finally we call didMoveToParentViewController on the child view controller passing in the parent view controller, which in this case is the new parent. Now you'll notice that we didn't call willMove at the beginning, and that's actually because the addChildViewController takes care of that for us, and so we're only responsible for the didMove.
So let's say in our application flow it's now come time to remove this view controller. And to do so, we start by calling the willMoveToParentViewController saying that nil, it's not going to have a parent at this point. And just as we saw before, we're calling the will and we won't be calling the did at the end of this.
Next, we'll remove the view from its superviews hierarchy. And then finally, call remove from parent view controller on the child, and that severs this relationship. And we're back to where we started. Now, there's a lot more -- there are a lot more interesting things that you can do here. And, again, Bruce is going to go into some more details to how you can do this in your applications.
So there's a few rules when it comes to, to custom containers. More like guidelines, but they're good to follow. First one is, well, the main one, is parents make the rules and children follow them. So parents add children, not the other way around. It's not a great idea to find some view controller that you want to be a parent of this child for whatever reason and use the containment API to establish that relationship by calling add child.
You'd want to use whatever the API that that container provides, because that will be its entry point. And you see we do that a lot with our containers, like push view controller on navigation controller, et cetera. So use that API, not the containment API. That's really meant only for subclassers.
And also, parents manage their children's views. There will be an example later as to why this makes as much sense, but this calls back to the centralizing responsibility. If all the views, the children views, are taking care of their own layout, things can quickly get confusing, especially when there needs to be communication. So it's best to let the root view controller manage the layout of its children's views.
So, quick summary. Why use view controllers? Well, they manage a view hierarchy, making that easy. They centralize responsibility. And they're very usable, which makes them this great size unit to vend and to get back from the system and use yourself. And using them effectively, one window with one root view controller, and then to build up your view controller hierarchy, take advantage of our system provided containers, of the presentation mechanism, and then finally creating your own custom containers. So now I'd like to invite Bruce on stage to talk to us about where we're going with view controllers.
Thank you, Matt. Good afternoon. My name's Bruce Nilo. My business card says I'm a view controller mechanic. Not a messy job, as some mechanic jobs are, but after this week I think I'm going to ask my boss for a promotion to view controller philosopher or something. I'm going to pick up where Matt left off.
I want to talk a little bit about the new APIs, some of the new APIs that we're adding to View Controller in iOS 6, and some of the APIs that we're going to say goodbye to. We're going to drill down a little bit more into view controller containment. Another way of thinking about that is how you might embed a view controller's view hierarchy into another one.
We're going to talk about auto rotation. We're kind of changing our approach to auto rotation in iOS 6 a little bit. And it's important to understand that. And then there's going to be a bunch of other stuff. The other stuff is actually important. It's kind of more of what's motivating some of these changes. So you get a sense of where we're going and where we're going to be taking view controllers into the future.
So I'm also going to demonstrate an application that I put together to highlight some of these points. I want to take a little digression, if you'll let me, to talk about that upside-down pachyderm in the picture. It really has nothing to do with this presentation. It's just a photo that I took, except I realized about a couple of days ago that it's actually a metaphor for how we sometimes evolve APIs. It can be a little bit of a balancing act. And I didn't realize it, but my subconscious was a little bit prescient there.
So this is going to be showing an application with a custom container with its own kind of application flow. You get a sense of it there. We're going to talk about best containment practices. We're going to talk about how to adopt the new auto-rotation behavior that I will be discussing shortly. And we're going to talk about how do you ensure that your view controller knows how to lay itself independently of the interface orientation that it's presented in. And finally, we're going to highlight some examples where some of these best practices should actually be applied.
So, let's talk about where view controllers are right now. And there's kind of this big general abstract point is that we want view controllers to be able to basically compose well with one another. And by compose, what I mean is that I should be able to present a view controller on top of another view controller that maybe is inside of a form sheet where a popover might pop up that has another view controller.
And all of these things interact and I can rotate it and the status bar winds up in the right place. It all just works consistently one with the other. That's a primary objective. View controllers should just work in all of the various presentation operators we have in UIKit.
But over time, some of the assumptions have changed a little bit. We've started to add new device types. We began to add many view controllers onto the screen at the same time. So this is kind of an evolution from where we started with the phone. And we're constantly adding new system view controllers that you can call out to from your own view controllers and from other view controllers. So the whole network of application flows that is possible has grown substantially.
And because of that, some of the internal APIs have to evolve so that we can keep them consistent. I guess another way of framing what I'm going to be talking about in terms of the APIs is I'm not going to be talking about the intelligent design of view controllers. controllers.
Sorry about that. So let's talk a little bit about How we've changed containment. Containment for view controllers, again, was really added in iOS 5 to meet that objective of being able to compose view controllers with one another in a consistent way. Prior to iOS 5, basically the only way to embed one view controller in another was to grab its view and slam it into the view hierarchy of another view controller's view, except for our system containers, which magically knew how to manage this relationship between view controllers. So that was no longer a very composable recommendation. We needed to provide a way for you as third-party developers to build your own custom containers.
And inform the system that you were doing so. So this picture that Matt has shown earlier demonstrates that before you add the view hierarchy of a child view controller into another view hierarchy, tell the system, tell the parent, hey, I am a child. And that allows us in the system to know that there's another informed or interested player in the mix when we start presenting and rotating. and the like.
All right, so I'm going to talk about some of the new API that we've added. There's one API which we've called Should Automatically Forward Appearance Methods. There used to be a much bigger method name, and I'll show you what that was a little bit later. Let's make believe we return no.
The default for this is yes, by the way, because most of the time the system takes handles, the forwarding of appearance. That's appearance methods are basically view will appear, view did appear, view will disappear, and view did disappear to its children at the right points in time. But you might want to build a container that actually doesn't want to use the default logic. You would override this method and return no.
So this is an example, some hypothetical container class, which has a revealed child method. And we've added two new methods. These actually weren't published as API on iOS 5, called BeginAppearanceTransition, Animated, EndAppearanceTransition. And basically these are used by a subclass of UIViewController that's implementing a container to inform its children that they are about to appear or disappear.
Why would you want to do that? Well, sometimes you might be building a complex container controller, and maybe the actual views of the children are tiled off-screen. And what you're really trying to do is you want to animate one of these off-screen views into front and center stage somehow.
And the system wouldn't do the right thing then, because you want to basically tell the view controller that's off-screen that it's appearing when you actually intend it to appear and animate it front and center. Normally, the way that the appearance callbacks are generated is tied to when a child view controller's view is added to the window hierarchy and removed from the window hierarchy.
So in such a case, if you have such a complex set of animations that you want to animate, you would return no from the method that was on the previous page, you would implement a method like this one, and you'd call those two new API methods highlighted below.
As I was saying, normally you would just add the subview. You wouldn't have to do anything else. But in this case, just to emphasize the point, we've created an animation using the UIView animation API. And inside the animation block, we are going to animate the frame into the visible section of the window.
One thing not to forget is that the container's appearance callbacks need to forward that information to its children as well, and their own view will appear if you did disappear. For example, if I have a container controller and some child presents another view controller full screen, that container is actually going to disappear. And so when it reappears, you want to tell its children in turn that they are reappearing. Now, I didn't show the other side of this, the disappearing, but it's an inverse, effectively, of these methods.
Matt made this point earlier. In general, what you want to do is you want to wrap all of the calls to the View Controller Containment API into a method that is effectively published for use by its clients. So, in this case, Reveal Child calls the internal View Controller methods that are highlighted there, and then anyone who wants to add a child into that container class would call Reveal Child.
Another point that Matt made that I'd like to reemphasize is the parent's responsible for the frames of its children. And by frames of its children, I mean the frames of the view of its children. The child view controller is responsible for its own view hierarchy. So in its view, we'll lay out subviews methods, and now in iOS 6, in its update view constraints method, it can go wild below itself.
It can access its bounds, it can move things around, but it can't indicate, or it shouldn't indicate, where it lives in its parent's view. And just to go back to this method again, that's what that method Adjust Frame for Child. That is a method that is implemented in the parent, in the container controller.
So there is a worst practice. I mean, kind of a semi-bad practice might be that you've implemented a parent and child, and the child adds its view directly to its parent. It's not great, but it's not the worst. The worst is that you add it on a class you have nothing-- you know nothing about. And this has actually happened. And sometimes it actually was a useful thing to do. But it is really bad practice. We might start throwing exceptions and really not being happy if that continues to happen. If Dante were alive, I might petition him.
Okay, we have a few other changes. This is that method. I'm a little bit embarrassed about this method. It got introduced in iOS 5. We're deprecating it now. I think it competed for the longest selector name in iOS. I'm not sure, and I'm not even going to try to say it. But we broke that method into two methods.
There's the should automatically forward rotation methods and the should automatically forward appearance methods, which we talked about. Typically, subclassers of UIViewController that are implementing containers really only care about one or the other and not both, so it made perfect sense to split the method and shorten the name. We discuss the begin appearance and end appearance transition methods. Just in case it's not obvious, it takes a Boolean, which is yes if we're talking about a view controller appearing or no if it's disappearing.
Auto rotation. So this is kind of a big set of changes. So in iOS 5 and earlier, I mean from the beginning, basically a view controller would override should auto rotate to interface orientation, and this method is queried prior to a rotation. Great. Perhaps less intuitively, it's also queried prior to presentations.
And sometimes you can end up with kind of weird mixed orientations where you're holding the device in portrait and something slides in in landscape and the status bar is off to one side. And this was all the way it was, this was the mechanics by which we were able to determine what to do.
Oftentimes the container controllers would ask their children, what is my supported interface orientation? So you'd push a navigation controller on, the navigation controller would be a review controller, you'd rotate it, and whether or not the navigation controller rotated was really a function of what the top view controller said to do. So sometimes it would rotate, sometimes it wouldn't rotate.
So there are a couple of problems with that. Let's go through a few of them. So the first one that kind of gives an inkling that something's a little bit amiss is, you know, what might support interface orientations is really not the same question as do I want to rotate.
These are not the same thing, but they're kind of used interchangeably by that method. It's a little bit odd as we're moving into this world of custom containers and multiple view controllers on a screen that children get to veto what the supported interfaces orientations of the parent are.
It kind of encourages a way of thinking about how you should lay yourself out based on your interface orientation. And back in the day when everything was kind of full screen on a phone, that made a lot of sense. It begins to make less sense. So let's look at that. I mean, interface orientation.
That's a method or a property. It's a property on UI view controller. And sometimes it just doesn't mean that much. So there's a view controller, a child view controller, and you could ask it what its interface orientation is. On iOS 5 and earlier, it's not exactly clear what that would return.
Similarly, you have a popover controller. You can ask the popover controller, "What is its interface orientation?" I can rotate and ask the popover controller the exact same question, "What is its interface orientation?" Now, some of you might know the answer to this. It's going to tell you that its interface orientation is portrait.
Part of the issue with that, in terms of, again, going back to composability and making things consistent, is that it kind of leads you to think, well, portrait is default layout, right? I mean, I'm now thinking that portrait is what I mean when I just want the default layout to occur. So we're trying to shift away from that type of thinking a little. So one other issue is that interface orientation is also tightly coupled with rotation. And guess what? In iOS 5, we changed when rotation callbacks actually are made.
So it didn't even work anymore on iOS 5. So if I presented a full-screen controller over another controller, rotated... Great. All of those rotation callbacks that Matt enumerated earlier get sent to the top view controller. That's great. Now when I dismiss the top view controller on iOS 5, those rotation callbacks do not get sent to the presenting controller.
So we've gotten a lot of bugs about that, and it is a change in behavior that we talked about on iOS 5 and in WWDC, in fact. So how do you target earlier iOS releases? So, pre-iOS behavior has to be checked by a selector check, basically. So, if you will layout subviews is not implemented, you know you're on a pre-iOS 5 system, which means that if you care about layout in a rotation like that, you got to implement it in the rotation callbacks. So, typically what we recommend is refactor your layout call, and if you're targeting something prior to iOS 5, you're going to need to call out to that method in the rotation callback. Otherwise, view will layout subviews is going to handle the job just fine.
So, moving forward. View controllers in general as reusable components should attempt to support all orientations. Certainly most of the view controllers that are vended by iOS are moving towards that -- into that direction. In fact, I think they all do that at this point. A child view controller should be able to lay out in any frame its parent specifies. So that kind of gets to, it really doesn't care about interface orientation, because maybe the parent is a subview off to the side somewhere.
So this deserves a little bit of comment. There's a canonical example where you present a video controller from portrait and the whole interface slides up in landscape because in general we want video to kind of display in landscape. So we do have a way that you can indicate that a presentation should come up in an orientation that's distinct from the actual current orientation that the device is at. And this is the one way that we are going to kind of allow these mixed orientations to continue forward.
And in fact, that's the API. It's called Preferred Interface Orientation for Presentation. A view controller that is being presented can indicate, hey, I always want to come up in landscape. It's one of my supported interface orientations, and the system will do that for you. Another small change here is that we only are going to be consulting the topmost full-screen controller. So that's typically the root view controller, but it can be any other controller that's presented full-screen.
And one of the big things is, like, an application should say, "These are the orientations I support." You know, a view controller might support everything, but an application might say, "I only want to be -- to run in a landscape set of orientations." And so we're making it a lot easier for the application to just do that, typically with no code written whatsoever. So, for example, inside of the Info.plist, there's a great interface in Xcode where you can actually specify that. Previously, this kind of had to do with launch orientations. Now it's also going to be respected in terms of what the application's preferred orientations are.
We're also going to add a method to the application delegate so the application delegate, if it wants, can compute what its preferred orientations are. All right, so let's summarize. We are deprecating that mouthful of a method. We are introducing a couple of new methods, supported interface orientations and preferred interface orientation for presentation, which I just discussed.
We're going to introduce a string constant. We will throw exceptions every now and then if you do wacky things in your application, like say you don't support any orientations or you have a preferred orientation that isn't one of your accepted or supported orientations, stuff like that. Now, I wanted to take a little bit of a detour and say, okay, here's reality. I have an iOS 5 app. You know, I have this thing that only works in portrait. I push something onto a navigation controller. I rotate to the landscape, and I really want to pop back into portrait, and I really need all of that stuff to work.
I don't have time to adopt the new approach you're talking about. So there is a way to do that, and it's going to require a little bit of work. If you're using one of our system containers, you might have to subclass it. You might have to subclass it just so you can override what the supported interface orientations are, and then you'll get mostly the same behavior that you were looking for or that you had in iOS 5.
The one exception to that is any use of set status bar orientation. I don't know how many of you guys actually use that, but that is going to have to be converted into a presentation if you want to kind of try to manipulate where the status bar actually is oriented.
So there are a couple other changes that I want to go through. Okay, that's the big one. I did say that set status bar orientation is being deprecated in iOS 6. The way to get that functionality is by breaking your application into presenting a controller that wants to be presented in a different orientation.
So, this auto-rotation stuff, the seed that you guys have has this capability in it. It's not turned on by default. You can turn it on basically by going into a schema of your application and setting that launch argument. Then it'll turn on the behavior for supported interface orientation. There are going to be a couple more changes that come out in the subsequent seeds, so please stay tuned and check release notes.
Okay, view will unload, view did unload. We're not going to call it anymore. I mean, there's kind of a cost-benefit equation and analysis that we went through. And in the early days, there was a real performance need for us to ensure that on memory warnings, we unloaded views. There was all kinds of graphics, backing stores, and so forth that would also get unloaded.
We now unload those independently of the view, so it isn't that big a deal for us to force views to be unloaded. And there were so many bugs where there would be pointers into unloaded views that didn't get cleared that at the end of the day, we didn't think it was worth automatically calling those. So we're going to deprecate those methods. You can still get the same behavior.
Your view controllers will still receive, did receive memory warning. And if they want to, they can nil out that view. It will work as expected. You might want to check first that your view isn't in the window before you release it. I make that point because some applications actually used ViewWillUnload and ViewDidUnload as a means to get rid of other resources as well that weren't necessarily related to the view per se. And so now that code might have to shift into DidReceiveMemoryWarning.
These were effectively deprecated in iOS 5, the present modal view controller, dismiss modal view controller. They have more or less a direct replacement called present view controller, which also takes a completion block. There's not much to say about that. So there's other new stuff, and I guess this can fall in the category of intelligent design. We've added constraint-based layout to UIKit, Auto Layout, and view controllers play really well with that.
There is a method called update view constraints, and you can kind of think of it as view will layout subviews, but it's working on constraints. It's going to get called if your constraints are modified, and I'm a big fan of that method. Storyboards are improving. They now support unwinding, which basically means you can actually indicate to go back to where you started, so you can pop a navigation controller or you can dismiss a view controller. So that's pretty cool.
There's a whole new kind of sub-feature where view controllers are intimately involved in helping an application do state restoration so that if a state is -- if an application is suspended or killed and resumed, you can have the illusion of coming right back to where you were when you last were using that application.
So I want to go move into the demo and highlight some points in code, the demo, God's willing. Before I do that, it will be helpful to talk a little bit about the structure of the demo app, just so you know what I'm talking about. We're implementing a custom view controller container. It is the root view controller of the window.
And let me make a little side comment about this. We have changed the behavior of when or how a view controller becomes the root view controller. For a long time, we've been admonishing everybody, call set root view controller, don't rely on adding a view controller's view to the window to make it the root view controller.
Well, in iOS 6, you can add a view controller's view to the window, but it's not going to be the root view controller, which means it won't get rotated. So, if you have patient callbacks, it'll be as if nothing's working. What you really need to do is call set root view controller now.
So, this custom container class is initialized with content. It so happens that the content for this demo app is just a photo browsing type of view controller. It could have been a page view controller that loaded other view controllers, but for purposes of pedagogy, it's a relatively simple content view controller. The container view controller manages a comment view controller, which is then associated with the content, which you can see on this screen.
And then it ties in with the rest of some of the features that are available on UIKit, like you can tweet the photo with the comment to any friends you want. You can email it. And that ties in with the new activity view controller, which is available on iOS 6 as well.
[Transcript missing]
Look at it on an iPad. So, if I do a long tap gesture, you'll see that the comment controller comes up. I can rotate it, and it lays out pretty nicely. It doesn't support upside down, which I guess is a little bit odd on an iPad. I would want it to support all orientations.
And I can bring up a camera. This is a full screen presentation. We can look at the switcher box here. And when I dismiss it, I'm going to notice a little problem here, and this is one of the things I want to talk to in code as well. You'll notice that the comment controller is off to the side now. So it kind of didn't get laid out the way we expect it to get laid out.
So what I'm going to do is -- Let's switch to the -- switch to Xcode. And I'm going to talk a little bit about how this code is structured. So to make it easy for myself, I created some pound defines here that you can see. So I can kind of enable like the different pieces of code that I want to talk to you about. Because if I actually had to type it right now, I'd run over time by far.
Before we go there, let's look at the supported interface orientation. So remember it didn't rotate upside down. Well, now I'm going to make it rotate upside down by clicking that. Next time we run it, we'll see it. And now let's look and see how we were dealing with the layout on that rotation.
Well, what we'll see is that the layout is being driven inside of the "will animate rotation to interface" orientation. That works great when the view controller is actually presented in front and center, but it doesn't work, as we discussed, when there's a full-screen presentation over that view controller and subsequently gets rotated.
So, we're going to fix that. And the way we're going to fix that is we're going to use the new Auto Layout. I will look at the code, but before we go to the code, I'm just going to change the pound defines. So let's search for Auto Layout.
I'm glossing over a little bit of the calls that are done in Auto Layout just because those aren't entirely germane to the view controller talk. But what you'll see here is that I've provided an implementation for update view constraints. And in case you haven't seen the talk, I recommend that you do download it or see the talk.
But what constraints do is that they create linear relationships between different view attributes. And then the layout engine figures out how to satisfy those constraints, possibly by moving sub views around. And what I decided was, you know, I didn't like the fact that the size of that comment controller was always the same.
It would be much better if it kind of tracked the aspect ratio of the actual interface orientation. So what these constraints do is, first of all, it says, I always want the -- Matt Gamble, Bruce Nilo I always want that comment controller to be in the center of the screen. So you'll see there's a relationship for equal on the center. I also always want it to be on the bottom of the screen. And finally, I want the width and the height to be a proportion of the width and the height of my containing super view.
And with those changes, more or less, we're going to run it again. Devices ready? All right. My pachyderm friend always makes me happy. So... Check that it's rotating now. Oh, look, this is upside down. You can tell because the cable's sticking up. So, that -- changing the info P list, really easy.
Change your supported interface orientations. I'm doing a long press now. And we're in the center. Notice how the aspect ratio of the comment container has changed. Let's see what happens when I present something full screen. I'm going to dismiss now. And we're centered. So using Update View Constraints, it's really simple.
It's really simple to figure out what your layout is in a way that's completely independent of the interface orientation of rotation. So it's certainly something that you should be looking forward to using in your apps. So one thing I wanted to talk about was -- it's okay. It's a comment container controller. I should be able to write a comment. So -- oh. So there's another problem.
And, you know, this is not a big problem, right? I mean, the keyboard came up, oh, God, I've got to move my views. There's a notification I can listen to. But what I wanted to, the reason I'm showing this is because there's different ways you might consider how should I move that, this particular view, the comment container, not the comment container, the comment view controller's view inside of the window hierarchy.
You might say, well, it's the comment container that needs to be moved. It can register for a keyboard notification and move it itself. So that's actually not what we want you to do or not what we recommend you do. Part of the reason for that is it kind of violates encapsulation. If you think about it, a container controller can have many children.
Maybe more than one of these things has to move. And so now each one of those is going to be like registering and listening and kind of cross-fighting. And so you're going to have to figure out how to do that. And so this is really the job of the parent view controller. So let's look at the code for how we do that. You'll notice there's a handy macro.
So in the viewDidAppear method, we register for the keyboard willShow and hide notifications. We unregister and viewDidDisappear. And then the implementation is really simple. Mind you, this is in the container view controller. So this is in the view controller that got initialized with the content photo controller and everything.
And what it's going to do, it's going to grab the geometry out of the keyboard notification, convert it to the correct coordinate system, and then it's going to call a method that it implements, which is to adjust the commentY position of that comment controller. And all that's doing is, guess what it's doing? It's recalculating the frame for that comment controller and then setting it. And it's setting it inside of an animation block so that it animates smoothly with the keyboard animation. So I'm going to run now with these changes.
A long tap again. This time I'm going to hit the keyboard and everything animates up smoothly. So you can enter a comment here. I can bring up the Activity View Controller. I can tweet it to my friends if I feel like it. And that demonstrates kind of a recommended way for doing keyboard avoidance.
And I just want to give some closing remarks about what you've seen. So in general, custom container controllers, embedding view controllers, you know, you're free to implement these. The best reason for implementing them is because you have a new application flow. You have something that you want to reuse that makes sense to reuse.
If you ever find yourself taking a view controller's view and really wanting to add it into another view hierarchy, you should immediately think there is a relationship between another view controller that I need to factor into the picture. Usually that will bring, sometimes it'll be very easy to do it, sometimes it'll bring into focus a part of the design that will make your application a lot more robust moving forward.
Having said that, we have lots of... As Matt pointed out, many, many system container controllers. And they provide a lot of functionality. They have a lot of knobs. And if one of those works, you should use it. But what's great is you can compose all of these things together.
You can use your own custom container controller. You can put in a system controller. Like in this application, I could have had a page view controller as one of the children. And then instead of this... Instead of like clicking up and down, you can have a page view controller. And then instead of a button to flip between my photos, I could have swiped just like we see in the photos app. So these changes that we make in UI view controller are really so that those types of compositions continue to work well for your applications.
Interface orientation, rotation, layout. Rotation callback should really be used if you want to participate in the rotation. Layout, for most view controllers, should really be independent of the question, am I in portrait, am I in landscape? There are exceptions to this, but in general, if you want to be able to compose your view controllers cleanly with other view controllers, you'll be making an effort to be looking in the bounds of your view controller's view.
And sometimes you don't even have to look at the bounds. I mean, with update view constraints, you can express these things pretty declaratively without even knowing that information. Again, you know, there's a couple of ways of expressing this, but the bottom line is that a view controller should never set its own frame.
Auto rotation is changing, and view controllers in general should strive to support all orientations. I realize I'm going to get some flack for this, except on the phone. It's okay not to support upside down on the phone. In fact, that's recommended. Apps can now easily indicate the orientations that they support. I mean, most of the time you're not even going to have to write any code. You're going to click something in the info P list and it's just going to work. And as I said, rotation callbacks are really for participating in the rotation.
Kind of big picture, Matt touched on this. View controllers are really the cornerstone of iOS apps. It's probably going to get more and more so. We are vending more view controllers as API. So, and we're going to continue to add features. So, they're useful and they make a lot of your tasks easier.
View controllers are a great abstraction. Design them with an eye to reuse. And really, think about how you want them to interact with each other in terms of your application flow. Not everything needs to be a view controller. It is more often the case than not that what you really want is you want to manage some subviews directly. And a view controller can do that just fine, and you can animate between your subviews.
And kind of the bigger take-home message for this kind of non-intelligent design of view controllers talk is really looking forward, you want to kind of try to track the new APIs as they're coming out. And at least don't participate in some of the deprecated APIs. If you do that, you're going to evolve with the whole ecosystem, and your apps are going to be more robust and work better. So I think that's all I have.
Actually, I have one more slide. There were, I did refer to a couple of supporting technologies. I believe there is a state restoration talk that's going to happen in 15 minutes. The other two talks, you're going to need to grab off the web. These are our contacts. Any bugs in the demo app, feel free to contact Jake Behrens.