Read iOS Programming: The Big Nerd Ranch Guide, 3/e (Big Nerd Ranch Guides) Online

Authors: Aaron Hillegass,Joe Conway

Tags: #COM051370, #Big Nerd Ranch Guides, #iPhone / iPad Programming

iOS Programming: The Big Nerd Ranch Guide, 3/e (Big Nerd Ranch Guides) (51 page)

For the More Curious: View Controller Relationships

The relationships between view controllers are important for understanding where and how a view controller’s view appears on the screen. Overall, there are two different types of relationships between view controllers:
parent-child
relationships and
presenting-presenter
relationships. Let’s look at each one individually.

 
Parent-child relationships

Parent-child relationships are formed when using
view controller containers
. Examples of view controller containers are
UINavigationController
,
UITabBarController
, and
UISplitViewController
(which you will see in
Chapter 26
). You can identify a view controller container because it has a
viewControllers
property that is an array of the view controllers it contains.

 

A view controller container is always a subclass of
UIViewController
and thus has a
view
. The behavior of a view controller container is that it adds the views of its
viewControllers
as subviews of its own view. A container has its own built-in interface, too. For example, a
UINavigationController
’s
view
shows a navigation bar and the view of its
topViewController
.

 

View controllers in a parent-child relationship form a
family
. So, a
UINavigationController
and its
viewControllers
are in the same family. A family can have multiple levels. For example, imagine a situation where a
UITabBarController
contains a
UINavigationController
that contains a
UIViewController
. These three view controllers are in the same family (
Figure 13.6
). The container classes have access to their children through the
viewControllers
array, and the children have access to their ancestors through four properties of
UIViewController
.

 

Figure 13.6  A view controller family

 

The first three ancestor-accessing properties of
UIViewController
are
navigationController
,
tabBarController
, and
splitViewController
. When a view controller is sent one of these messages, it starts traversing the family tree until it finds the appropriate type of view controller container. If there is no ancestor of the appropriate type, these methods return
nil
.

 

Additionally, every
UIViewController
has a
parentViewController
property. This property holds the closest view controller ancestor in the family. Thus, it could return a
UINavigationController
,
UITabBarController
, or a
UISplitViewController
depending on the makeup of the family tree.

 
Presenting-presenter relationships

The other kind of relationship is a presenting-presenter relationship, which occurs when a view controller is presented modally. When a view controller is presented modally, its
view
is added
on top of
the view controller’s
view
that presented it. This is different than a view controller container, which intentionally keeps a spot open on its interface to swap in the views of the view controllers it contains. Any
UIViewController
can present another view controller modally.

 

Figure 13.7  Presenting-presenter relationship

 

There are two built-in properties for managing the relationship between presenter and presentee. A modally-presented view controller’s
presentingViewController
will point back to the view controller that presented it, while the presenter will keep a pointer to the presentee in its
presentedViewController
property (
Figure 13.7
).

 
Inter-family relationships

A presented view controller and its presenter are
not
in the same view controller family. Instead, the presented view controller has its own family. Sometimes, this family is just one
UIViewController
; other times, this family is made up of multiple view controllers.

 

Understanding the difference in families will help you understand the values of properties like
presentedViewController
and
navigationController
. Consider the view controllers in
Figure 13.8
. There are two families, each with multiple view controllers. This diagram shows the values of the view controller relationship properties.

 

Figure 13.8  A view controller hierarchy

 

First, notice that the properties for parent-child relationships can never cross over family boundaries. Thus, sending
tabBarController
to a view controller in Family 2 will not return the
UITabBarController
in Family 1. Likewise, sending
navigationController
to the view controller in Family 2 returns its
UINavigationController
parent in Family 2 and not the
UINavigationController
in Family 1.

 

Perhaps the oddest view controller relationships are the ones between families. When a view controller is presented modally, the actual presenter is the oldest member of the presenting family. For example, in
Figure 13.8
, the
UITabBarController
is the
presentingViewController
for the view controllers in Family 2. It doesn’t matter which view controller in Family 1 was sent
presentViewController:animated:completion:
, the
UITabBarController
is always the presenter.

 

This behavior explains why the
DetailViewController
obscures the
UINavigationBar
when presented modally but not when presented normally in the
UINavigationController
’s stack. Even though the
ItemsViewController
is told to do the modal presenting, its oldest ancestor, the
UINavigationController
, actually carries out the task. The
DetailViewController
is put on top of the
UINavigationController
’s
view
and thus obscures the
UINavigationBar
.

 

Notice also that the
presentingViewController
and
presentedViewController
are valid for every view controller in each family and always point to the oldest ancestor in the other family.

 

You can actually override this oldest-ancestor behavior (but only on the iPad). By doing so, you can specify where the views of the presented view controller family appear on the screen. For example, you could present the
DetailViewController
and its
navigationController
so that it only obscures the
UITableView
but not the
UINavigationBar
.

 

Every
UIViewController
has a
definesPresentationContext
property for this purpose. By default, this property is
NO
, which means the view controller will always pass presentation off to its next ancestor, until there are no more ancestors left. Setting this property to
YES
interrupts the search for the oldest ancestor, allowing a view controller to present the modal view controller in its own view (
Figure 13.9
). Additionally, you must set the
modalPresentationStyle
for the presented view controller to
UIModalPresentationCurrentContext
.

 

Figure 13.9  Presentation context

 

You can test this out by changing the code in
ItemsViewController.m
’s
addNewItem:
method.

 
    UINavigationController *navController = [[UINavigationController alloc]
                                initWithRootViewController:detailViewController];
    
[navController setModalPresentationStyle:UIModalPresentationFormSheet];
    
[navController setModalPresentationStyle:UIModalPresentationCurrentContext];
    [self setDefinesPresentationContext:YES];
    [navController setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
    [self presentViewController:navController animated:YES completion:nil];
}

After building and running on the iPad, tap the
+
icon. Notice that the
DetailViewController
does not obscure the
UINavigationBar
. Make sure you undo this code before moving on to the next chapter.

 

Other books

The King's Gold by Arturo Pérez-Reverte
Katy Kelly_Lucy Rose 04 by Lucy Rose: Working Myself to Pieces, Bits
Lost Time by D. L. Orton
Nine Man's Murder by Eric Keith
Logan by Melissa Foster
The Peoples King by Susan Williams
Merry Humbug Christmas by Sandra D. Bricker
To Love a Bear by Kay Perry


readsbookonline.com Copyright 2016 - 2024