KEVIN CATHEY: Good afternoon, welcome back from lunch.
I guess if you guys are watching the video you are like, lunch, I'm eating breakfast right now.
Or whatever meal you just ate, wherever you came from, welcome to threading issues with core data.
I'm just kidding.
No, we are here to talk about interface builder.
My name is Kevin Cathey I'm one of the interface builder engineers and we're going to do something a little different today, we're going to show you some of the new features of interface builder but I want to do two other things, one, we're going to give you some more advanced content, tips and tricks, best practices, interface builder under the hood, and then second we're going to look at interface builder and how it helps you through each step of the development of your application.
Let me explain a little bit more.
Here is you.
You have a bright idea.
Now, thankfully there are some other people who also think your idea is pretty bright too, but here is the problem.
They live all around the world and they use all different kinds of Apple products.
What are you doing to do?
First you're going to think about your application, what are the features it's going to have?
What will be the different clumps of shared functionality that you're going to have?
When you have those you will look at an individual scene and within that scene you will go down and actually work at the view level.
Okay so if we step back for a second, going from a view all the way up to deploying multiple products in languages, that's a huge process and interface builder helps you save boat loads of time in each one of those steps.
We can take this entire process and boil it down into three main phases which works out great for an agenda for the session.
We're going to start by talking about interface builder at design time.
I'm going to give you guys some best practices and then we're going to pull the hood up a little bit and look at interface builder at build time, and then finally we're going to spend a large section of this presentation talking about interface builder at run time, both how you can interact with interface builder at run time and also how can you take advantage of many of the different run time OS features for making applications adaptable.
Let's dive in and start talking about interface builder at design time and the best way to talk about interface builder at design time is to show you interface builder at design time.
Now, before I switch over to the demo here, in this demo I'm going to show you five tips and tricks and five best practices.
We're going to do that by adding a new feature to an application we are working on which is a road trip application.
We're going to add a new tab to it that allows me to follow my friends who are currently going on a road trip.
In this application, I'm going to be working off of a specification from my designer, and I'm enjoying this for two reasons, one if you are working with a designer to help maybe give you guys some of the lingo that you might interact with when working with a designer, and then secondly if you're not working with a designer to show you that building applications and the best processes going into that can be done with or without a designer.
With a static mock up like the one you see on the screen there's two main pieces of data you will grab from this, one, the layout, where things go.
Two, the appearance, what things look like.
We're going to start by working on the layout of the application, and that brings us to our best practice number one, adopting auto layout and specifically adopting stack views.
Adopting auto layout means taking the relationships between views and co-defying those in objects called constraints.
For those of you who have used auto layout in the past, you'll know that working with raw constraints is very flexible, very powerful.
It's some other things too.
For example, you will sometimes need to specify the same sets of constraints repeatedly and that's where stack views come into play.
If constraints are taking the old, you know, position and size information and abstracting that into relationships, stack view takes it a step farther and takes those relationships and abstracts it into behaviors.
Let's go ahead and adopt stack view in our application.
Let me switch over to Xcode.
Here is the beginnings of our awesome new feature.
Adopting stack view in interface builder literally I don't think it could be simpler.
I'm just going to select the views that I want to put into a stack view and then using the stack button down here in the bottom of the canvas, I just click it, and now we have a stack view.
Once we have a stack view, we can adjust several of the different properties that a stack view has.
Now, in tomorrow's auto layout session they're going to go into all of the different properties that stack view has but one that we're going to focus on now is called alignment.
If I switch back to my mock-up, you can see that my designer has specified to baseline a line these labels.
What is baseline alignment?
Baseline alignment basically allows you to take text that is different font sizes and make it look nice and aligned.
If you have textual objects like buttons and labels and segmented controls you're going to want to baseline align these versus using top or center or bottom.
So let's go back to interface builder and what we can do is if I go into the attributes inspector I can change the alignment of my stack view to be baseline aligned.
Now, there is first and last year, so if you have multi-line text, you can target either the first line of text or the last line of text.
In this case it's single line so it doesn't really matter so we'll go with first.
So let's continue adopting stack view, I can take this stack in this label and put it in stack view and I can add our image view.
As I'm embedding in stack view, interface builder is automatically inferring the different attributes such as the alignment and the orientation.
Now that we have this outer stack view we want to position this within our table cell which is not a stack view.
And to do this we're going to use raw constraints.
I'm going to go to my tie fighter and go ahead and open up add constraints and I want to clarify two things in this pop-up, the first is what is up with the layout margins?
What are these things.
Layout margins are insets from a view that by default the system provides some values for and if you use the default layout margins they can be automatically adapted based upon different context, for example, the device or the view hierarchy.
Generally if you have content like buttons, labels, things that people interact with or see, then you are going to want to constrain things to the margins if it's not constrained to another sub view.
If you have something like an image view that kind of sits behind your entire table view cell that makes perfect sense to constrain it to the edges instead so even if those margins change your imagery will still be in the background.
If I uncheck constraints, constraints and margins you can see larger values coming into play.
Interface builder defaults to margins which is helpful because that's exactly what I want.
Second thing I want to clarify is this update frames here which I am going to use.
Update frames is the process of interface builder moving your views in the IB canvas to match what the constraints would be at run time.
When I'm adding constraints I have a couple of options for doing this.
If I say all frames in container it means for all of the sub views in my table view cell, move them to where the constraints would tell them to be at run time.
However, if I have a really large view with lots and lots of sub views, I might only want to move the things that I'm currently working on at that instance, and that's what this middle option is, it only moves the items that are actually going to be in the new constraints I'm adding.
Now, I only have one thing so it doesn't matter so we will do all frames and add those constraints and now we are on our way.
Okay. Next thing I want to do is change the alignment of the items inside the stack view.
Another example of doing that.
I will change that to fill and now, that's not exactly what I'm looking for, right?
Stack views are built on top of auto layout, which means that you can use constraints to fine tune your layout.
So if I want to make this image view have a one-on-one ratio, even though it's in a stack view, I can still add constraints so I can add an aspect ratio and then change the multiplier to be one to one.
The next thing I want to do is add spacing in between that image view and the right hand content.
Because my designer would like there to be some padding there.
Now, the stack view that I need to change the spacing on is fully occluded by labels and other stack views?
How can I get at it?
There are a couple of ways you can get at occluded views in interface builder.
I could use the jump bar or I could use the outline view, but I'm going to show you my personal favorite which brings us to Xcode pro tip number one which is fast selection.
If I shift right click or control left click.
I can get a menu of everything underneath the mouse at that point and then I can easily select the thing that I'm looking for.
Once I have it selected I can change the spacing to what I need and there we go.
The last thing I want to show you with stack view is how you can use multiple stack views nested together to get the exact layout you are looking for.
If we go back to our specification here, you can see this set of labels our designer would like it to act as a unit and be centered vertically within the table view cell.
We can do this by putting the right hand content in another stack view and adjusting the alignment.
Let me show you that.
I will use my fast selection again to get to the stack view.
I'm going to embed it in another stack view.
You can see the blue got a little darker to show you that, and now I can change my alignment to center.
Now, alignment affects the non-stacking direction.
Because this is a vertical stack view, it's going to be adjusting the horizontal alignment, but I want to affect the vertical alignment so I will change the access to horizontal.
And you can see with stack views I can get the exact layout I'm looking for with very minimal constraints.
Our recommendation when adopting auto layout is to use stack views and to try to use stack views first and then only when you need to actually use raw constraints.
We think you're going to be able to build most of your UIs using stack views.
Which makes it easy to build.
It makes it really easy to experiment with different layouts without having to adjust a bunch of constraints and it also makes it very maintainable when you go back in later and have to edit one of your documents.
The next thing we want to do is start looking at the appearance of our application.
And the first thing I'm going to do is prepare our canvas for some design time.
To do this I'm going to go under the edit canvas menu.
And interface builder has lots of options for customizing what's drawn on the canvas.
For example, these blue backgrounds the stack view is drawing for me are really helpful at layout time so I can see exactly how big that stack view is going to be, but at design time I want to see what it's actually going to look like at runtime.
So I will just go ahead and turn those off.
Okay. In the appearance section of this demo, we are going to look at three best practices with using interface builder.
If we go back to our specification, we'll see the first one.
Our designer has specified headline and body instead of an explicit font or font size.
What are these?
These are called dynamic type styles.
They are defined by the system and when you use them, it allows the system to automatically adapt what the effective size and font is going to be at runtime based upon your user's preferences.
For example, the user can adjust accessibility to have a larger font.
Your application when using dynamic type will automatically adapt to those font changes and if you are using auto layout, the views will all flow around it.
So we can adopt this really easily inside of interface builder.
I can just select the label I want to adopt dynamic type for and the inspector, I can pick one of the font styles instead of an explicit font.
In this case, I will choose headline.
I have already adopted it for the rest of my labels so we are done with dynamic type.
The next thing we are going to do is we are going to bring that image view to life and we are going to use two best practices for this.
One is designables, and two is inspectables.
Designables allows us to see our custom drawing code right inside the interface builder canvas.
So let's go ahead and get some code for that.
I want to go ahead and open up the product navigator.
Let's add some files.
Tony, who is going to come up later just air dropped me this code, so let's go ahead and add that to our project, and I'm going to go ahead and open this, and in opening it, I'm going to show you guys Xcode pro tip number three, which is advanced navigation.
If I option shift click this file, I get a little hud.
This hud allows me to target where I want to open this file.
So I can choose a new tab, I can choose a new split.
If I have multiple tabs I can even target specific splits within tabs that aren't even open.
And as I use command I can also even open it in a new window.
In this case, I'm just going to do the assistant editor.
Adopting designables is a really simple two step process.
All you have to do is mark a subclass of UI view with IB designable, and then set that custom class with an interface builder.
So if we select our image view or what's going to be our image view, change the identity inspector, and add in our customs subclass here.
Interface builder is going to build my project, launch a process for rendering, bring in my code, render it and show me that in the canvas.
And if I change the code, it's going to automatically take those new changes, build them, and apply them within interface builder as well.
The next thing I want to go is adopt inspectables.
You can see I have a couple different properties here marked add IB inspectable.
When you mark a property as IB inspectable it allows interface builder to generate an inspector for you.
If I select image view, go to the attributes inspector, you can see that those three properties I marked as inspectable are showing up now in our inspector and we can quickly adopt these.
So I can say I'm going to add that little image there.
We're going to do our stroke with.
I think the spec said two, if I recall correctly.
And we can give it a nice border color as well.
Now, what's going on here is that designables and inspectables are working together to help you rapidly iterate on your design.
I haven't built and ran once and I can see exactly what I'm going to get at runtime because of the power of designables and inspectables.
And that's our section on adjusting the appearance of our application with the dynamic type, designables and inspectables.
Now, we all know that our applications are not made up of a single scene, okay, unless you write the flashlight app, but generally you're going to have multiple scenes in your application.
And if I zoom the storyboard out I can see there is a lot more scenes in my application.
You can bring a scene into the flow of your application using segues.
To make a segue I can control drag from a view controller or an object that can initiate a segue and select the type of segue I want to add.
In this case I will add a relationship segue to add another tab to our tab bar controller.
Now, once we actually have made the segue, I realize that I kind of want to be able to navigate within this table view controller, so I am going to embed this in a navigation controller.
I will choose the editor menu, embed and embed this inside a navigation controller.
I want to point out something that interface builder is doing to help us here.
This is another Xcode pro tip.
Interface builder is showing us a nav bar and a tab bar for this particular scene.
Now these objects are not added to the scene, interface builder has not added these to your scene but what it is doing is helping you see what your application is going to look like at runtime given some context.
This makes it really easy to be able to design for different contexts without having to build and run.
You can see what your simulated metrics are, which is the name of the feature, by selecting your view controller.
And then going to the attributes inspector and you can see my simulated metrics.
Now, right now they are all saying inferred.
Inferred just basically means use the context around me.
We know we are inside a tab bar controller, we know that we're inside a nav controller so interface builder knows which bar to show.
I can override these to be whatever I need.
So, for example, I could say actually I want to look like what is it going to look like with prompt if I had prompt text in there?
What if the top bar was black.
I will put this back on inferred.
All of these metrics do not affect your actual application at runtime with one exception and that's the size simulated metric.
The size simulated metric will actually change the size of your view controller but generally you're going to put it into a view controller hierarchy which will resize it, but it's also helpful if you are creating free form view controllers, for example, and want to set your own size.
It's also helpful if you are wanting to be able to design with a specific size in mind even if your application is going to run on multiple devices.
The spec I was given was for iPhone 6 Plus, so I can change to a 5.5 in screen size and be able to edit as if the view controller was going to be that size.
There's other features of interface builder we are not going to talk about today which allows you to see what your view controller will look like on multiple devices at the same time using the preview assistant, but this is really helpful for just being able to edit with a particular context in mind.
Let's go back to inferred and let's finish off our view controller.
Give it a title, your friends.
Let's add some bar button items.
We had add one for being able to invite a new friend.
And with Xcode 7 I can add multiple bar items to my navigation item.
It's the small features, right?
Let's finish off this by adding a segue to present this guy modally, and if you zoom out we have a great start to your application.
Just like I would refactor my code into separate files based upon the reuse of it or related functionality, I can do the exact same thing now with interface.
If I just select the view controllers that I want and go under the editor menu, I can select refactor to storyboard.
You can type in a name, I will call it follow because this is our follow tab.
Interface builder is going to create a new storyboard, move those view controller scenes into the storyboard and put a reference to the scenes in the old storyboard.
Now, it's really easy to collaborate with storyboards.
And it's the big features.
Let's go back to slides.
We have looked at a number of different things here so let's recap.
I have given you five best practices.
We have adopted stack views and dynamic type to make your applications adaptable.
We have adopted designables and inspectables to be able to rapidly iterate on your design without having to build and run.
And finally we have used storyboard references to make sure we are properly modularizing our interface just like we would do for our code.
I have also given you a couple of tips that I hope you guys are going to find useful as you're using interface builder like being able to select things, being able to customize the canvas, open files exactly where you want them using multiple bar items and, of course, taking advantage of simulated metrics to see at design time what you are going to get at run time.
But what happens when I hit build?
Let's talk a little bit about what interface builder is doing for you at build time.
Now, to do this we are going to have to take a step back and look again at design time and where we are going with run time.
At design time you are working with XML documents.
At build time a process called IB tool takes these documents and compiles them into nib files.
Nib files are small, very optimized binary files and it uses a process called keyed archiving for creating these.
I have a few examples of what this could look like.
When interface builder is compiling a storyboard it's doing two things first, it's trying to maximize the performance of your application and secondly it's also minimizing the number of nib files created.
If I have a view controller with a view and a bunch of sub views, interface builder, the build time is going to create a nib file for the view controller and create a nib file for the view.
Why two nib files.
By having separate nib files for both the view controller and the view, this means the view hierarchy can be loaded on demand.
With this other example here, with the table view controller and navigation controller things get even a little more interesting.
Again, interface builder is trying to minimize the number of nib files it's creating with a relationship segue we know that those two view controllers go together, so we will put those in the same nib.
Next we are going to give you a nib file for the table view and also a nib file for each of the cells.
So how does this play out at run time?
When you allocate a storyboard instance using UI storyboard, API, initially all you are allocating memory for is the UI storyboard instance itself.
No view controllers no views yet.
When you instantiate your initial view controller it will load the nib for that initial view controller but, again, no view hierarchy has been loaded yet until someone actually asks for it.
Similarly, if I gave that navigation controller and table view controller an identifier then I could use the instantiate API to be able to get that view controller instance, but, again, the view has not been loaded into memory until someone actually asks for it.
How about those table view cells?
This is where it gets fun.
So interface builder is going to automatically take table view cells, nibs, and register them with the table view under your reuse identifier that you set, that table view cell.
Now, what this means is that these cells are not going to be loaded until someone actually DQs the cell with the identifier.
Now, it also means that once the nib run time has loaded that nib file into memory, it can rapidly instantiate it.
So there are a couple of take aways for talking about interface builder at build time.
The first is performance.
Interface builder is working on your behalf to make the performance of your applications as good as we can.
Nib files are only loaded on demand and nib files themselves are really small and optimized.
Secondly, interface builder has reuse of different nib files.
For example, on the table view cell that's we saw, once the runtime has the nib file it's able to reinstantiate it very very quickly as new cells are needed.
Finally hopefully you can see the lifecycle of how things are happening between build time and runtime so you know how to interact with the different objects like your view controllers and your view hierarchies.
We talks about interface builder at design time.
We have pulled the hood up a little bit at build time, but we're going to spend the rest of the session talking about interface builder at runtime and what happens when you have all those different products and languages.
To do that, I'm going to bring up my colleague, Tony Ricciardi.
TONY RICCIARDI: Thank you Kevin.
My name is Tony, and I also work on interface builder.
So Kevin just gave you some great best practices for building your UI at design time and then he gave you a peek at what happens behind the scenes at build time.
Now, I'm going to give you a few examples of how you can add dynamic behavior to your UI at run time.
Interface builder supports three general mechanisms for controlling your UI at run time.
First of all, you can create connections between your storyboard and your source code using IB actions and IB outlets.
You can also customize the behavior of your segues or dynamically instantiate and add view controllers using the storyboard API.
And finally, you can use auto layout or size classes to specify how your UI adapts as the size of its container changes.
Let's start with connections.
In Swift, IB outlets are by default implicitly unwrapped optionals.
If you have an outlet between a view controller and one of the views in its hierarchy you can safely unwrap that optional after viewed load.
Sometimes you will have an additional property stored on your view controller that affects the appearance of that view, and in that case, you will want to unwrap that property using optional chaining within the did set observer of that property.
In case your outlet hasn't been connected yet.
IBAction is allowing you to respond to events sent from gesture recognizers and controls.
You might use an action just to update some state without navigating away from the current view.
You can also use an IBAction to dynamically choose which segue you want to perform after an event.
Next we have the storyboard API.
The class UI storyboard or NS storyboard on the Mac allows you to grab a reference to a storyboard file and instantiate view controllers from that storyboard.
It's extremely useful if you have a reusable piece of UI you want to repeatedly instantiate.
It's also the only way you can connect multiple storyboards in your app if you are displaying prior to iOS 9 or Mac OS 10, 11.
We also have a lot of great API hooks on UI controller to allow you to customize behavior of your segues.
This year we have made a lot of improvements to segue unwinding on iOS.
We have made it a lot easier to subclass UI storyboard segue or NS storyboard segue.
If you would like to learn more about that, please come to our What's New in Storyboard session tomorrow morning.
Finally we have adaptability.
Interface builder supports two technologies to help you adapt your UI to different container sizes.
First of all, we have auto layout which allows you to size and position your views relative to each other so that you are not relying on hard coded frame values.
In some situations, you will want to make a significant change to your layout as the width or height of the container crosses a certain threshold, and in those situations we have another great feature called size classes which makes that very easy to do.
Now, I would like to give you a demo of how you can apply these three general techniques to work with interface builder at run time.
Let's head over to Xcode.
Today we will be building a UI to keep track of the activity of your friends on their Roadtrip and plan on integrating this into Kevin's Roadtrip app later on.
As you can see in this UI, I have three rows of posts, and within each row, I show the top three posts from that category.
If we take a look at the storyboard for my app, you can see I have implemented this UI using a stack view.
Within this stack view, I have three container views.
A container view allows you to embed one view controller inside of another one, and that's extremely useful if you have a reusable piece of UI like this that you want to use multiple times within the same scene.
My embedded view controller over here has a stack view of its own.
In this stack view holds multiple instances of this post view controller down here.
The number of posts that I show in each category is controlled by a user setting and so I don't know it statically at design time.
Instead of using container views like I do over here, for this view controller, I instantiate it using the storyboard API.
I refer to this view controller from code using its storyboard ID up here which I have set up here in the identity inspector.
Let's take a look at the code where I do that.
I'm going to use the jump bar to navigate to the source code file for my post stack view controller.
So you can see down here in my view.load method I'm using the storybook API instantiate that post view controller.
Specifically, I'm using the storyboard property that I'm getting from UI view controller and then I'm calling instantiate view controller with identifier.
And that identifier I pass in is the same string we just saw in the identity inspector.
After I add or after I instantiate the child, I add it as a child view controller.
And then I add it's view as an arranged sub view of my stacking.
So the storyboard API is great for instantiating and adding a child view controller, but what if you want to add a sub view that is not associated with a different view controller.
Let's head back to the storyboard for an example.
If we take a look up here at the top of my activity view controller, you can see I have a view up here in the scene doc.
The scene doc allows you to store top level objects alongside your view controller and you might put a view in your scene doc if you don't want that view to initially be part of your view at run time.
In Xcode 7 when you put a view in your scene doc and you select it, it shows up in its own editor above the view controller.
This means you can now visually edit your views right here in the storyboard canvas, even if they are not initially part of your view hierarchy.
This view here shows an error message if there is a problem connecting.
So what I want to do now is create an outlet connection to this view and then add it from code if there is a problem connecting.
I want to open up the assistant editor and that's going to take me to the implementation for my activity view controller.
And then I'm just going to control drag over to the source code and when I let go, I get a little pop over allowing me to configure my outlet connection.
But the first option here is whether I want to make an outlet or outlet collection.
Outlet collections are great for adding or removing groups of sub views or constraints all at once, but in my case, I just want to add a single view, so I'm going to choose outlet.
Next we can name the connection.
I'm going to call it connection error view.
And the last option I want to point out is the storage type, which can either be strong or weak.
In general you should make your outlet strong, especially if you are connecting an outlet to a sub view or to a constraint that's not always going to be retained by the view hierarchy.
The only time you really need to make an outlet weak is if you have a custom view that references something back up the view hierarchy and in general that's not recommended.
So I'm going to choose strong and I will click connect which will generate my outlet.
Now, I'm just going to paste in some code, and this code is an implementation of view did load.
And I check if there is a problem connecting and if it so, I add my connection error view to the top of my root stack view and I'm accessing both views using outlets.
Let's take a look at this in the simulator.
So as you can see, there was a problem connecting, and now my view is showing up right at the top as we expected.
So this UI looks great on a full screen iPad.
What happens if I run it in split view?
I'm just going to drag the split to be in the middle of the screen and let go, and you can see my UI is not doing a great job of adapting to the narrow width.
What I really want is for these posts to lay out vertically when the width is compact so that each post can get the full width of the screen to itself.
And at the same time, when we are back in full screen mode, I want my stack views to continue to lay out horizontally like they are now.
So to do that, I'm going to head back to my storyboard, and I'm going to close the assistant to give us a little more room.
And I'm going to select my stack view and head over to its attributes inspector.
You can see currently my stack view is configured to lay out horizontally, and next to this access property there is a plus button.
This plus button allows you to add a size class customization.
A size class is an abstract range of sizes in one or two dimensions and in my case I want to customize this property for when the width is compact.
And since I don't care about the height dimension, I will choose any height.
When I do that, I get a new row in my inspector and the value I put here is going to take effect when the width is compact and the height is anything.
I will change that to vertical now.
And I will run this again.
So once again we are in full screen and our stack views are still laying out horizontally.
Now, let's try this in split view mode again.
We got it.
So there you go, now our accessory view is laying out vertically like we wanted and each post gets the full width of the half screen.
So that was just one way you can use size classes.
You can override a property value for single property, but you can also add and remove entirely new sub views or constraints, and if you want to learn more about all you can do with size classes, we had a fantastic session on that last year called building adaptive apps with UI kit.
That's all I have for the demo, so let's head back to the slides.
Kevin and I just showed you a ton of great techniques to help you get the most out of interface builder.
Let's review the most important ones.
First of all, you saw how you can build flexible user interfaces that don't rely on hard coded frame values using auto layout constraints and stack views.
Then Kevin showed you how you can rapidly iterate on the appearance of your custom views using designables and inspectables.
We introduced a new feature to help you modularize your UI called storyboard references, and then I showed you how you can use the storyboard API to repeatedly instantiate reusable components.
And finally, you saw how you can make your UI adapt to different container sizes using size classes.
If you would like more information, you can post on the forums or contact our evangelist and we also highly recommend checking out our What's New in Storyboard session tomorrow morning as well as our two auto layout sessions later that day.
Once again if you want to learn more about size classes please check out our building adaptive app session from last year.
And finally if you want to learn more about troubleshooting your auto layout within Xcode we had a great session on that in 2013.
And thank you all and please enjoy the rest of the conference.