Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Start a free Basic trial
to watch this video
The boilerplate included with the template is really useful for getting started but much of the code we need to learn has been written for us. Let's get rid of most of it and start from scratch.
-
0:00
We're gonna start here by deleting the Master and DetailViewController files.
-
0:07
There's a lot going on in each of these files, and you'll probably get a better
-
0:11
understanding by starting with a lot less boilerplate in writing that code yourself.
-
0:16
So we move all of these to the trash.
-
0:18
Let's add a new file to the project.
-
0:20
And this time, we're going to select Cocoa Touch subclass or Class.
-
0:26
We want a subclass of UITableViewController.
-
0:30
And we're going to call this file, rather than the default TableViewController,
-
0:34
we'll call this ContactListController.
-
0:39
This controller is going to serve as the view controller for our master view.
-
0:44
So we'll hit next, and we'll add this to the project.
-
0:47
Now, one of the reasons we do this, instead of creating an empty swift file,
-
0:50
is because we get some boilerplate code by default.
-
0:54
Let's get rid of all of the commented code in here, so delete everything.
-
1:01
And might as well get rid of this.
-
1:04
There we go.
-
1:05
We need another controller for the detail view.
-
1:07
And here, we're going to add another TableViewController.
-
1:12
You'll see why later on.
-
1:14
We're going to call this one ContactDetailController.
-
1:19
And again, we'll delete all the commented code in here as well,
-
1:24
just to clear things up and make things less confusing.
-
1:30
We still need to make a couple more changes.
-
1:33
So head over to the main.storyboard file.
-
1:35
And in the Master scene shown here, we need to change this underline class to
-
1:39
contact list controller since we don't have that master detail or
-
1:43
master view controller file anymore.
-
1:46
So click on this,
-
1:46
click on the identity inspector and make sure you select ContactListController.
-
1:52
Let's also change this title to Contacts.
-
1:56
For the detail theme down here, right now, there's just a plain old view controller.
-
2:01
So click delete to get rid of it, and
-
2:04
then we're going to drag out from the Object Library, a Table View Controller.
-
2:09
Now, you might have to zoom out to make all this fit neatly, there we go.
-
2:17
Select the table view controller,
-
2:19
change the underline classic ContactDetailController.
-
2:23
Now, we also need to set this TableViewController as the root
-
2:27
view controller of this navigation controller.
-
2:29
And to do that, pretty simple,
-
2:31
right-click on the navcontroller, and you'll see a triggered segue.
-
2:36
It says, root view controller, and
-
2:38
just drag over from the outlet to the table view.
-
2:42
If you try and run the app now though, it will fail.
-
2:45
And this is because now that we've switched out the master and detailed view
-
2:49
controller, the Split View Controller doesn't know how to handle a new set.
-
2:54
These are brand new classes.
-
2:56
So you'll see here that we have an error, and
-
2:59
this error is located in the AppDelegate class.
-
3:03
When we first built our first iOS app, we talked about the AppDelegate for a bit.
-
3:09
The AppDelegate is the main point of interaction between the app and
-
3:13
the system, and other apps on your device.
-
3:16
The AppDelegate is the root object of our app.
-
3:19
Like the UIApplication object itself,
-
3:21
the AppDelegate here is the single routine object, and is always present at runtime.
-
3:28
This AppDelegate performs several roles and, oftentimes,
-
3:31
it can get bloated because of this.
-
3:33
In response to key changes in the state of your app, for example, if your app is
-
3:38
temporarily interrupted, or if there are changes in the execution state of your
-
3:42
app, such as when your app transitions from the foreground to the background.
-
3:46
It also responds to notifications originating from outside the app,
-
3:50
such as remote notifications, also known as push notifications,
-
3:54
low memory warnings, download complete notifications, and many more.
-
3:58
But the crucial bit for us is that the AppDelegate also contains the very first
-
4:03
bits of code run when an app is open.
-
4:06
Well, we didn't really have to switch out the Table View Controllers.
-
4:09
We could have used the Master in detail defaults.
-
4:12
This way, we actually have to figure out what's going on in the AppDelegate
-
4:15
in this new template.
-
4:17
What's different?
-
4:18
And all of these should hopefully broaden your understanding of the role of
-
4:21
this object place, and how your app is set up when it first launches.
-
4:25
So when the app is run and
-
4:26
it's done launching, the system calls application didFinishLaunchingWithOptions.
-
4:31
And we can override this method to add any customizations, post-launch.
-
4:37
Typically, this is where we set the viewController as the rootViewController
-
4:41
on an apps window.
-
4:43
Since this project uses a splitViewController, the code in here
-
4:48
sets up the splitViewController as the windows root controller, and
-
4:53
then customizes the navigationController embedded in the master view.
-
4:57
So all of this is the navigationController and
-
4:59
subsequent views that were set up in the storyboard file by default.
-
5:04
We have two navigation controllers embedded in a splitViewController.
-
5:07
One for the master view and one for detail.
-
5:09
And each of those navcontrollers contains our Table View Controllers.
-
5:14
So complicated but out of the box, the good thing is that this
-
5:17
app should also work on an iPad or on an iPhone 7+ in landscape.
-
5:23
Now, the last bit of code in here, the important bit,
-
5:26
is the line of code right before the returning statement.
-
5:29
That one right there, which sets up the AppDelegate as the delegate for
-
5:34
this splitViewController in this app.
-
5:37
Why does this matter?
-
5:39
Well, because using a splitViewController means understanding
-
5:42
how it handles presenting views.
-
5:44
What you're about to learn isn't necessary for understanding table views at all.
-
5:49
But this aspect, a split view controllers can drive you mad,
-
5:52
because you might think that your code is setting up the table view incorrectly.
-
5:57
When in reality,
-
5:58
the problem is with your understanding of how a splitViewController works.
-
6:03
Let's take a look at how a sample table view appears on regular displays,
-
6:07
then compact displays using a Split View Controller.
-
6:11
So, on the left, is how you would see the table view on an iPhone in portrait mode.
-
6:16
And on the right is an iPhone 7+ in Landscape.
-
6:21
On the Portrait View, the Split View Controller handles the primary and
-
6:25
secondary views, or the master detail interface, as we've come to expect.
-
6:29
If you tap on a row in the master, the Detail View Controller
-
6:33
is pushed onto the navigation stack on top of the master or the primary view.
-
6:38
In a landscape mode on the same phone,
-
6:40
the split view controller handles things differently.
-
6:43
The primary view controller or master is on the left side, and
-
6:47
the detail screen is also on the screen already, on the right.
-
6:52
If you tap something in the master list,
-
6:54
the detail view shows it right on the right side.
-
6:57
And all of this again happens out of the box which is super useful
-
7:01
because without having to write any additional logic,
-
7:04
we have a set up that works better on larger screens.
-
7:07
What happens though when you rotate that 7+ from landscape to portrait mode?
-
7:13
This is the interesting bit, and where it starts to get mildly complicated.
-
7:17
When you rotate from the expansive display in landscape
-
7:20
to the compact one in portrait,
-
7:23
the system first needs to pick a view controller to act as the primary view.
-
7:28
If you look at the storyboard scene we have set up, the only indication
-
7:33
that one view controller is acting as the primary is that detail segue.
-
7:38
The detail segue is enough information though, and the Split View Controller
-
7:42
figures out which one it should use as the primary controller.
-
7:46
Okay, so why does a choice of the primary controller even matter?
-
7:52
Well in a compact display mode, in portrait view,
-
7:55
the secondary view controller is pushed onto the primary controller.
-
8:00
And this behavior allows for the typical navigation hierarchy with the back button,
-
8:05
and the behavior of going back from detail to master.
-
8:09
So if, for example, the split view controller decided to pick the detail
-
8:13
view as the primary view, then the list would be pushed on top of the detail view.
-
8:18
And if we hit back, we would go to the detail view, not the other way around.
-
8:22
If we wanted to modify this behavior, we can implement the Primary View Controller
-
8:27
for collapsing method of UISplitViewControllerDelegate protocol
-
8:32
to explicitly state which controller acts as the primary.
-
8:36
But again, the split view controller knows how to do this out of the box.
-
8:39
It has enough information here.
-
8:41
But there's another aspect of this behavior that we need to handle.
-
8:45
So let's bring that portrait and landscape view side by side again.
-
8:49
Once the primary view controller has been chosen, the next step is the secondary
-
8:54
controller, the detail, that needs to be merged into the primary controller.
-
8:59
So again, by default, the Split View Controller does the right thing, and
-
9:02
merges the detail view on top of the master.
-
9:06
When it does this, so when you rotate from landscape to portrait,
-
9:11
the system displays the detail view on top, already pushed on top of the stack.
-
9:16
This is convenient because if you have something selected, when you rotate it,
-
9:19
you're still in the detail view.
-
9:21
So you're looking at the information that you want to see.
-
9:24
Except, what about when we haven't selected anything for the detail view?
-
9:29
If, for example, we're holding our plus iPhones in landscape
-
9:33
where we see the side by side display, and then we rotate it to
-
9:36
portrait without having selected an item from the master view.
-
9:40
Then, the split view controller is going to correctly
-
9:43
select the master view controller as the primary controller.
-
9:47
And it's going to merge the secondary view, or the detail with the primary
-
9:51
by pushing it onto the navigation stack and collapsing the whole thing.
-
9:55
As you can see in this case though, since we didn't select anything in the master
-
10:00
prior to rotating, the detail view's empty.
-
10:02
And the user now has to navigate back to the main view, select something, and
-
10:06
then get the detail view again.
-
10:09
In such an event, we can provide an implementation for
-
10:11
a second delegate method.
-
10:13
And if you scroll to the bottom of the app delegate,
-
10:16
you'll see this method right here.
-
10:17
And this is split view controller collapse secondary on to primary view controller.
-
10:23
In this method, the split view controller asks the delegate to
-
10:26
adjust the primary view controller.
-
10:29
And to incorporate the secondary view controller into the collapsed interface.
-
10:34
After this method returns,
-
10:36
the splitViewController removes the secondaryViewController from its
-
10:40
viewControllers array, leaving the primaryViewController as its only child.
-
10:45
Okay, so all that sounds complicated.
-
10:47
What does it mean?
-
10:48
Well, by using this method,
-
10:49
we can either choose to show the primaryViewController as the main view.
-
10:54
Or depending on the situation, we can choose to add the secondaryViewController
-
10:58
back to the stack to mimic the default behaving.
-
11:02
And we do this simply by returning true or false, because as you can see,
-
11:06
this method returns a Boolean value.
-
11:08
Returning false tells the splitViewController to use its default
-
11:12
behavior to try and
-
11:13
incorporate the secondaryViewController into the collapse interface.
-
11:18
Returning true, on the other hand,
-
11:20
tells the splitViewController not to apply any default behavior.
-
11:24
What it all comes down to is we return true in cases where we do not want
-
11:29
the secondaryViewController's content incorporated into the resulting interface.
-
11:34
What we'll do here is figure out if we have a contact to display first.
-
11:40
If we do, then we'll display the secondary controller on top of the primary,
-
11:44
otherwise, we're going to just display the primary, that list.
-
11:47
Now, luckily for us,
-
11:48
much of this code is already implemented because we used a template.
-
11:52
We just need to change a few details.
-
11:55
So first step here, this line of code,
-
11:58
we check to see that there is a secondary controller to work with.
-
12:03
Remember that when a view controller is embedded in a navigation stack,
-
12:07
the navigation controller is the main controller, for all respects and purposes.
-
12:12
So here, if we don't have a secondary view controller,
-
12:14
which we're checking to see that it's a nav controller.
-
12:17
Then we're just going to return false, which results in just the primary
-
12:22
controller being shown since we're resorting to default behavior, right?
-
12:27
At that point, only the primary controller exists, okay?
-
12:30
Well, what if we have a secondary controller, that navigation controller?
-
12:35
After that, we check to see that the navigation controller contains the correct
-
12:39
view controller that we want to act as the secondary controller.
-
12:43
Now, by default here, the template came with the detail view control subclass
-
12:47
which is what it's checking for.
-
12:50
We need to change this here since we removed that default.
-
12:53
We want to check if an instance of contactDetailController is available.
-
13:00
If it isn't, again, we're going to return false because that means that
-
13:03
we only want to show that primary controller the list of contacts.
-
13:08
This happens for the same reason, in that, without a secondary controller,
-
13:11
the default is to just show the primary.
-
13:14
For the last step, this is the important part,
-
13:16
we need to check if the contact detail controller actually has an instance
-
13:21
of a contact to show and isn't just an empty view controller.
-
13:26
So the code in here is checking some property called detailItem, and
-
13:30
making sure it's not nil.
-
13:32
Our secondary controller, ContactDetailController,
-
13:35
doesn't have a property named detailItem.
-
13:38
Instead, what we would need to check is if we have a contact
-
13:42
associated with the controller.
-
13:43
So let's go to that TableViewController subclass, and add a property.
-
13:48
We'll call this contact, and this is an optional contact.
-
13:53
You should know why this is an optional property, but
-
13:56
no big deal if you don't remember.
-
13:58
You'll always be initializing this TableViewController using init coders,
-
14:02
since we're using storyboards to build our layout.
-
14:05
Since we won't be able to assign an initial value to the contact store
-
14:09
property during initialization, we have to create an optional property and
-
14:12
assign nil to start off.
-
14:15
Okay, so now that we have this contact in this bit of code,
-
14:19
we'll check to see that the contact isn't nil.
-
14:22
If it is nil, then we're going to return true.
-
14:25
Returning through means the secondary controller is going to be discarded.
-
14:29
So in this case, if we rotate back and the secondary controllers contact properties
-
14:34
nil, then it's discard it and we see the master list.
-
14:38
If you run this app now using a seven plus simulator,
-
14:45
and you rotate the device, you'll see that we get the expected behavior.
-
14:49
All right, so here we have a 7 plus simulator and you can't see much because
-
14:54
it's blurred, but I'm going to go to hardware and rotate left.
-
14:57
And you'll see now that we have the master detail view side by side and
-
15:00
they're both table view controllers.
-
15:03
Now at this point, there's no information in the master to select so
-
15:07
obviously there's not going to be any information in the detail controller.
-
15:11
So if we rotate back, we would like to see the primary view
-
15:15
on top rather than the detail and that is the behavior we get.
-
15:19
Now, this was a large detour but we finally have our project properly set up
-
15:24
and you understand for the most part how a split view controller does things.
-
15:29
In the next video, let's get some data up on the screen.
You need to sign up for Treehouse in order to download course files.
Sign up