Loaded and Appearing Views

Now that you have two view controllers, the lazy loading of views that you learned about earlier becomes more important.

When the application launches, the tab bar controller defaults to loading the view of the first view controller in its array, the BNRHypnosisViewController. This means that the BNRReminderViewController’s view is not needed and will only be needed when (or if) the user taps the tab to see it.

You can test this behavior for yourself – when a view controller finishes loading its view, it is sent the message viewDidLoad.

In BNRHypnosisViewController.m, override viewDidLoad to log a statement to the console.

-​ ​(​v​o​i​d​)​v​i​e​w​D​i​d​L​o​a​d​
{​
 ​ ​ ​ ​/​/​ ​A​l​w​a​y​s​ ​c​a​l​l​ ​t​h​e​ ​s​u​p​e​r​ ​i​m​p​l​e​m​e​n​t​a​t​i​o​n​ ​o​f​ ​v​i​e​w​D​i​d​L​o​a​d​
 ​ ​ ​ ​[​s​u​p​e​r​ ​v​i​e​w​D​i​d​L​o​a​d​]​;​

 ​ ​ ​ ​N​S​L​o​g​(​@​"​B​N​R​H​y​p​n​o​s​i​s​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​l​o​a​d​e​d​ ​i​t​s​ ​v​i​e​w​.​"​)​;​
}​

In BNRReminderViewController.m, override the same method.

-​ ​(​v​o​i​d​)​v​i​e​w​D​i​d​L​o​a​d​
{​
 ​ ​ ​ ​[​s​u​p​e​r​ ​v​i​e​w​D​i​d​L​o​a​d​]​;​

 ​ ​ ​ ​N​S​L​o​g​(​@​"​B​N​R​R​e​m​i​n​d​e​r​V​i​e​w​C​o​n​t​r​o​l​l​e​r​ ​l​o​a​d​e​d​ ​i​t​s​ ​v​i​e​w​.​"​)​;​
}​

Build and run the application. The console reports that BNRHypnosisViewController loaded its view right away. Tap BNRReminderViewController’s tab, and the console will report that its view is now loaded. At this point, both views have been loaded, so switching between the tabs now will no longer trigger the viewDidLoad method. (Try it and see.)

To preserve the benefits of lazy loading, you should never access the view property of a view controller in initWithNibName:bundle:. Asking for the view in the initializer will cause the view controller to load its view prematurely.

Accessing subviews

Often, you will want to do some extra initialization of the subviews that are defined in the XIB file before they appear to the user. However, you cannot do this in the view controller’s initializer because the NIB file has not yet been loaded. If you try, any pointers that the view controller declares that will eventually point to subviews will be pointing to nil. The compiler will not complain if you send a message to one of these pointers, but whatever you intended to happen to that view object will not happen.

So where can you access a subview? There are two main options, depending on what you need to do. The first option is the viewDidLoad method that you overrode to spot lazy loading. The view controller receives this message after the view controller’s NIB file is loaded, at which point all of the view controller’s pointers will be pointing to the appropriate objects. The second option is another UIViewController method viewWillAppear:. The view controller receives this message just before its view is added to the window.

What is the difference? You override viewDidLoad if the configuration only needs to be done once during the run of the app. You override viewWillAppear: if you need the configuration to be done and redone every time the view controller appears on screen.

There is a subview of the BNRReminderViewController’s view that needs some extra work – the date picker. Currently, users can pick reminder times in the past. You are going to configure the date picker to only allow users to select a time that is at least 60 seconds in the future.

This is something that will need to be done every time the view appears, not just once after the view is loaded, so you are going to override viewWillAppear:.

In BNRReminderViewController.m, override viewWillAppear: to set the minimumDate of the date picker.

-​ ​(​v​o​i​d​)​v​i​e​w​W​i​l​l​A​p​p​e​a​r​:​(​B​O​O​L​)​a​n​i​m​a​t​e​d​
{​
 ​ ​ ​ ​[​s​u​p​e​r​ ​v​i​e​w​W​i​l​l​A​p​p​e​a​r​:​a​n​i​m​a​t​e​d​]​;​

 ​ ​ ​ ​s​e​l​f​.​d​a​t​e​P​i​c​k​e​r​.​m​i​n​i​m​u​m​D​a​t​e​ ​=​ ​[​N​S​D​a​t​e​ ​d​a​t​e​W​i​t​h​T​i​m​e​I​n​t​e​r​v​a​l​S​i​n​c​e​N​o​w​:​6​0​]​;​
}​

Build and run the application. Select the Reminder tab and confirm that the date picker will only allow the user to select a date in the future.

If you had overridden viewDidLoad instead, then datePicker’s minimumDate would be set to 60 seconds after the view was initially loaded and would likely remain unchanged for the entire run of the application. If the app ran for very long, then users would soon be able to select times in the past. Sometimes a view controller’s view may get destroyed and reloaded, but that is not the typical behavior on newer devices.

Wondering about the animated flag on this method? It indicates whether the appearance or disappearance transition is animated or not. In the case of UITabBarController, the transition is not animated. Later in the book, in Chapter 10, you will use UINavigationController, which animates view controllers being pushed on and off screen.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset