iOS Programming View Controllers 視圖控制器 編程
1.1 canvas
A view controller is an instance of a subclass of UIViewController. api
一個view controller 是一個UIViewController的子類。 app
A view controller manages a view hierarchy. ide
一個view controller 管理一個視圖樹。 性能
It is responsible for creating view objects that make up the hierarchy, for handling events associated with the view objects in its hierarchy, and for adding its hierarchy to the window. ui
它負責建立view 對象,處理event,把視圖樹加到window上。 this
In this chapter, you will create an application named HypnoNerd. In HypnoNerd, the user will be able to switch between two view hierarchies – one for being hypnotized and the other for setting a reminder for hypnosis on a future date. atom
在本章中,你將建立兩個視圖,並能切換。 spa
step1:Create a new iOS project (Command-Shift-N) from the Empty Application template. Name this project HypnoNerd
建立一個新應用名字爲HypnoNerd。
Step2
:
Step3: 建立UIViewController 的子類
Step4:Open BNRHypnosisViewController.h and change the superclass to UIViewController.
@interface BNRHypnosisViewController : UIViewController @end
打開BNRHypnosisViewController.h,將繼承NSObject改爲繼承UIViewController
1.2 The view of a view controller
As a subclass of UIViewController, BNRHypnosisViewController inherits an important property: @property (nonatomic, strong) UIView *view;
做爲UIViewController的子類,它繼承了一個很重要的屬性:UIView.
This property points to a UIView instance that is the root of the view controller's view hierarchy.
這個屬性指定了一個UIView實例,而這個實例就是view controller
A view controller's view is not created until it needs to appear on the screen. This optimization is called lazy loading, and it can often conserve memory and improve performance.
view controller 的view 老是到要顯示到屏幕上時才建立。這樣能解決內存和提高性能。
There are two ways that a view controller can create its view hierarchy:
有兩種方式建立view controller 的view hierarchy.
(1)programmatically, by overriding the UIViewController method loadView.
編程 重寫UIViewController 的loadView方法。
(2)in Interface Builder, by loading a NIB file. (Recall that a NIB file is the file that gets loaded and the XIB file is what you edit in Interface Builder.)
在Interface Builder 經過加載NIB文件。
1.3 Creating a view programmatically
編程方法建立View
step 1 :Open BNRHypnosisViewController.m and import the header file for BNRHypnosisView. Then override loadView to create a screen-sized instance of BNRHypnosisView and set it as the view of the view controller.
在view controller 裏重寫loadView,將controller的view 設置爲你要想要的view。
#import "BNRHypnosisViewController.h" #import "BNRHypnosisView.h"
@implementation BNRHypnosisViewController
- (void)loadView
{
// Create a view
BNRHypnosisView *backgroundView = [[BNRHypnosisView alloc] init];
// Set it as *the* view of this view controller
self.view = backgroundView; }
When a view controller is created, its view property is nil. If a view controller is asked for its view and its view is nil, then the view controller is sent the loadView message.
當一個view controller 被建立時,它的view property 是nil。當view controller被 要求view的時候,若是view 是空,那麼view controller 將會發送loadView 信息。
The next step is to add the view hierarchy of the BNRHypnosisViewController to the application window so that it will appear on screen to users.
接下來要要將view controller 的view hierarchy 加載到application window這樣就能顯示給用戶了。
1.4 Setting the root view controller 設置 root view controller
There is a convenient method for adding a view controller's view hierarchy to the window: UIWindow's setRootViewController:. Setting a view controller as the rootViewController adds that view controller's view as a subview of the window.
用一個方便的方法UIWindow的setRootViewController方法,能夠將view controller 的view hierarchy 到窗口。
Setting a view controller as the rootViewController adds that view controller's view as a subview of the window. It also automatically resizes the view to be the same size as the window.
設值view controller 做爲rootViewController 自動將view controller 的視圖做爲window 的subview . 而且將自動調整view 的尺寸和window 同樣。
導入你想做爲根視圖控制器的控制器頭文件到Delegate方法中。
#import "BNRAppDelegate.h"
#import "BNRHypnosisViewController.h"
@implementation BNRAppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch
BNRHypnosisViewController *hvc = [[BNRHypnosisViewController alloc] init];
self.window.rootViewController = hvc;
self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible];
return YES;
}
The view of the root view controller appears at the start of the run of the application. Thus, the window asks for it when setting the view controller as its rootViewController.
root view controller 的view出如今應用一開始。所以window請求view 在設置view controller 做爲rootViewController .
咱們能夠猜測setRootViewController 應該是這樣的:
- (void)setRootViewController:(UIViewController *)viewController
{
// Get the view of the root view controller UIView *rootView = viewController.view;
// Make a frame that fits the window's bounds CGRect viewFrame = self.bounds; rootView.frame = viewFrame;
// Insert this view as window's subview [self addSubview:rootView];
// Update the instance variable _rootViewController = viewController;
}
1.5 Another UIViewController 另外一個UIViewController
The BNRReminderViewController's view will be a full-screen UIView with two subviews – an instance
of UIDatePicker and an instance of UIButton
這個視圖控制器的view 將包含兩個UIVIiew 一個UIDatePicker and UIButtoon。
In addition, the view controller will have a datePicker property that points to the UIDatePicker object.
另外View controller 將會有一個dataPicker 屬性指向UIDatapicker。
Finally, the view controller will be the target of the UIButton and must implement its action method addReminder:.
view controller 將會成爲UIButton的target,而且必須實現action 方法addReminder .
1.6Creating a view in Interface Builder 在Interface Builder 上建立一個view.
#import "BNRReminderViewController.h"
@interface BNRReminderViewController ()
@property (nonatomic, weak) IBOutlet UIDatePicker *datePicker; @end
@implementation BNRReminderViewController
- (IBAction)addReminder:(id)sender
{
NSDate *date = self.datePicker.date;
NSLog(@"Setting a reminder for %@", date); }
@end
The IBOutlet and IBAction keywords tell Xcode that you will be making
these connections in Interface Builder
IBOutlet 和IBAction 關鍵字告訴Xcode 你將在Interface Build 鏈接。
Create a new XIB file by selecting File → New → File.... From the iOS section, select User Interface, choose the Empty template, and click Next
1.7Creating view objects 建立新的view object
Search for UIView. Drag a View object onto the canvas. By default, it will be screen-sized, which is what you want.
把一個View 對象拖到Canvas 。默認狀況下它將是與屏幕匹配的。
find a Date Picker and a Button in the library and drag them onto the view.
In the document outline to the left of the canvas, you can see your view hierarchy: the View is the root and the Picker and Button are its subviews.
在document outline ,你將看到view hierarchy . view is the root .picker and button 是subview.
When a view controller gets its view hierarchy by loading a NIB file, you do not override loadView. The default implementation of loadView knows how to handle loading a NIB file.
當一個view controller 經過NIB 文件得到view hierarchy ,你不須要重寫loadView. loadView的默認實現知道如何處理NIB文件。
The BNRReminderViewController does need to know which NIB file to load. You can do this in UIViewController's designated initializer:- (instancetype)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle;
view controller 須要知道哪一個NIB文件須要加載。你能夠用UIViiewcontroller的指定初始化方法:- (instancetype)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle;
In this method, you pass the name of the NIB file to be loaded and the bundle in which to look for that file.
在這個方法中你傳遞了NIB文件的名字,以及在哪一個bundle裏查找這個文件。
• Bundle (OS X), a type of directory in NEXTSTEP and OS X
bundle 的含義:在Nextstep 和OS X的一類目錄
// This will get a pointer to an object that represents the app bundle NSBundle *appBundle = [NSBundle mainBundle];
// Look in the appBundle for the file BNRReminderViewController.xib BNRReminderViewController *rvc =
[[BNRReminderViewController alloc] initWithNibName:@"BNRReminderViewController" bundle:appBundle];
self.window.rootViewController = hvc;
self.window.rootViewController = rvc;
The bundle that you are getting by sending the mainBundle message is the application bundle.
經過發送 mainBundle 得到的bundle 是應用程序的bundle。
This bundle is a directory on the filesystem that contains the application's executable as well as resources (like NIB files) that the executable will use.
這個bundle是包含了應用執行或者能執行的資源的文件系統的一個目錄。
When the corresponding NIB file was loaded, these objects were instantiated. But you have not made connections to link the instantiated objects with the BNRReminderViewController in the running application.
當NIB文件加載時,這些對象初始化,可是你沒有將ViewController 與初始化對象鏈接。
This includes the view controller's view property. Thus, when the view controller tries to get its view added to the screen, an exception is thrown because view is nil.
這包括view controller 的一個view .當view controller 加載時,一個exception拋出了,由於view是nil。
1.8 Connecting to File's Owner
The File's Owner object is a placeholder – it is a hole intentionally left in the XIB file. Loading a NIB, then, is a two-part process: instantiate all of the objects archived in the XIB and then drop the object that is loading the NIB into the File's Owner hole and establish the prepared connections
File's Owner 對象是一個代理。 加載一個NIB,分爲兩步:1. 實例化全部在Xib中得對象。2.接着把在NIB中加載的對象放到File owner 中並創建鏈接準備。
So if you want to connect to the object that loads the NIB at runtime, you connect to the File's Owner when working in the XIB. The first step is to tell the XIB file that the File's Owner is going to be an instance of BNRReminderViewController.
因此若是想把在NIB文件中加載的對象,你必須鏈接File'owner 。第一步即是告訴File'owner 是view controller 的一個實例。
Identity inspector for File's Owner
Now you can make the missing connections. Let's start with the view outlet.
In the dock, Control-click File's Owner to bring up the panel of available connections. Drag from view to
the UIView object in the canvas to set the view outlet to point at the UIView
you declared the datePicker outlet as weak. Declaring outlets as weak is a convention from earlier versions of iOS. In these versions, a view controller's view was automatically destroyed any time that system memory was low and then was recreated later if needed.
你在datePicker outlet 屬性設置爲weak。聲明outlet爲weak類型是早起iOS版本的傳統。在這些版本中, 若是內存太低,那麼view controller 的view 將在任什麼時候間自動銷燬,當須要的時候再從新建立。
Ensuring that the view controller only had weak ownership of the subviews meant that destroying the view also destroyed all of its subviews and avoided memory leaks.
確保view controller 只有weak ownership 的subview意味着當destroy the view的時候也destroy 全部的子視圖,避免內存泄露。