1. 程式人生 > >iOS開發:第一個iOS程式分析——AppDelegate.h檔案和檢視View、檢視控制器ViewController

iOS開發:第一個iOS程式分析——AppDelegate.h檔案和檢視View、檢視控制器ViewController

上一篇文章iOS開發:第一個iOS程式分析——代理,生命週期函式中主要介紹了iOS使用Objective-C開發的兩個主要檔案main.m和AppDelegate.m和控制程式生命週期的函式,接下來將介紹另外兩個檔案:AppDelegate.h檔案、UIViewController.m檔案和iOS開發中的View和ViewController。

開啟AppDelegate.h檔案:

先看一下AppDelegate類,前面說過,AppDelegate是作為Application的代理,這個程式中的AppDelegate不僅負責控制程式的生命週期,而且負責控制程式初始介面(初始StoryBoard)的顯示,因此該代理類必須能夠訪問到初始介面的介面元素。

明白這點,就不難了解KZX AppDelegate類中為什麼會有UIWindow的一個引用了。如下

該檔案只有以下寥寥幾行程式碼:

<span style="font-family:Comic Sans MS;font-size:14px;">#import <UIKit/UIKit.h>

@interface KZXAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end
</span>

除去匯入標頭檔案的語句,檔案由@interface開始宣告到@end結束宣告,可以看到,確實該代理類持有一個UIWindow類的例項,該UIWindow例項即代表了該檢視控制器所負責控制顯示的視窗檢視(即一個螢幕介面),讀者朋友可以嘗試把這一句刪去,會發現執行程式後是黑漆漆一片,因為代理無法找到應該在哪裡顯示檢視。自然沒有介面。

那麼為什麼代理要持有UIWindow的例項而不持有其他檢視的例項呢?

先來看看官方文件對於檢視的說明(View):

“Views not only display themselves onscreen and react to user input, they also serve as containers for other views. As a result, views in an app are arranged in a hierarchical structure called the view hierarchy. The view hierarchy defines the layout of views relative to other views. Within that hierarchy, view instances enclosed within a view are called subviews, and the parent view that encloses a view is referred to as its superview. Even though a view instance can have multiple subviews, it can have only one superview.At the top of the view hierarchy is the window object.

 ”

"檢視不僅在螢幕上顯示他們本身、對使用者的輸入做出反應,而且也能夠作為容器來為其他檢視提供服務。所以一個app中的檢視是被組織成一種層次結構的,叫做檢視層級。檢視層級決定了不同但是相關的檢視之間的佈局和排版。在檢視層級裡面,多個檢視圍繞某個特定的檢視來佈局,則該特定的檢視稱為父檢視,而圍繞父檢視佈局的其他檢視稱為子檢視。儘管一個檢視能夠擁有多個子檢視但是一個檢視不可能有多個父檢視。在檢視層級的最高層次是window物件"。

注意最重要的是最後一句話,也就是說如果把檢視層級看成一棵樹的話,那麼這棵樹的根就是window物件,因此學過樹資料結構的都知道,持有根節點當然能方便地訪問其他所有節點,這就是AppDelegate持有UIWindow的原因。


注意到@interface AppDelegate後還帶了: UIResponder <UIApplicationDelegate>,在Objective-C中,繼承寫法跟C++一樣都是用冒號(半形)來表示,所以這一句表示了該代理類繼承了UIResponder類,但是後半部分<UIApplicationDelegate>則體現了Objective-C還有的 協議 這種概念,協議類似於Java中的介面,與介面不同的是實現協議可以不實現協議的所有方法,具體要看協議宣告方法時是用@optional還是@required。可在Xcode中command+點選UIApplicationDelegate看看,如下。

<span style="font-family:Comic Sans MS;font-size:14px;">@protocol UIApplicationDelegate<NSObject>

@optional

- (void)applicationDidFinishLaunching:(UIApplication *)application;
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions NS_AVAILABLE_IOS(6_0);
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions NS_AVAILABLE_IOS(3_0);

- (void)applicationDidBecomeActive:(UIApplication *)application;
- (void)applicationWillResignActive:(UIApplication *)application;
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url;  // Will be deprecated at some point, please replace with application:openURL:sourceApplication:annotation:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation NS_AVAILABLE_IOS(4_2); // no equiv. notification. return NO if the application can't open for some reason

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application;      // try to clean up as much memory as possible. next step is to terminate app
- (void)applicationWillTerminate:(UIApplication *)application;
- (void)applicationSignificantTimeChange:(UIApplication *)application;        // midnight, carrier time update, daylight savings time change

- (void)application:(UIApplication *)application willChangeStatusBarOrientation:(UIInterfaceOrientation)newStatusBarOrientation duration:(NSTimeInterval)duration;
- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation;

- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame;   // in screen coordinates
- (void)application:(UIApplication *)application didChangeStatusBarFrame:(CGRect)oldStatusBarFrame;
</span>


...省略若干行


接下來就是KZXViewController.m(KZXViewController.h幾乎沒有內容):

先來看看Apple對檢視控制器的一些官方文件(ViewController):

“In an iOS app, you use a view controller (UIViewController) to 

manage a content view with its hierarchy of subviews.A view 

controller isn’t part of the view hierarchy and it’s not an element 

in your interface. Instead, it manages the view objects in the hierarchy

and provides them with behavior.
You also use view controllers to implement transitions from one type of 

content to another. Because iOS apps have a limited amount of space in 

which to display content, view controllers provide the infrastructure 

needed to remove the views of one view controller and replace them 

with the views of another.”


在一個iOS 的 app 中,你使用一個檢視控制器(UIViewController)來

管理一個具有內容的檢視以及他的子檢視層級。注意檢視控制器並不是視

圖層級的一部分,而且也不屬於使用者介面的元素。實際上,他是用來管理

檢視層級中的檢視物件的,並且為他們定義一些響應行為(來作為與使用者

的互動)。當然也可以使用檢視控制器來作為兩個(種)具有內容的檢視

的過渡,畢竟iOS app(實際上應該是iOS的大部分裝置螢幕)只有有限的

空間來顯示內容,檢視控制器提供了刪除檢視和替換檢視的一些必須的基礎函式。“


由以上可知,一個檢視的檢視控制器實際負責兩部分——管理該檢視的

子檢視層級,管理該檢視與其他檢視的轉換。

回到KZXViewController.m檔案,該檔案中定義瞭如下函式:

<span style="font-family:Comic Sans MS;font-size:14px;">- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

- (void)viewDidLoad

- (void)didReceiveMemoryWarning

</span>

initWithNibName使用一個xib檔名(檢視佈局檔案)來初始化檢視

的子檢視層級,viewDidLoad在初始化完畢後呼叫(兩個函式對應“管理

子檢視層級”功能),而didReceiveMemoryWarning通常在記憶體不足時

被警告時呼叫,此函式一般用來釋放一些資源和資料。

關於體現檢視控制器“管理該檢視與其他檢視轉換”的功能,

讀者朋友可以開啟UIViewController標頭檔案看宣告的方法對應。


總結:

1.代理通過適時呼叫委託方的函式來控制對委託方的訪問,ApplicationDelegate

作為整個app的代理不僅要控制app的生命週期,還要負責app入口介面,因此

ApplicationDelegate持有app入口介面的檢視層級根檢視——UIWindow。

2.檢視控制器負責管理該檢視的子檢視層級以及管理該檢視與其他檢視的轉換。

檢視控制器不屬於檢視,不在檢視層級之內。


下一次我們將介紹MainStoryBoard.storyboard檔案以及常用的一些檢視控制元件的使用。