你使用類UIViewController 的自定義子類來呈現你的應用程序的內容。大多數自定義的視圖控制器都是內容視圖控制器,也就是說,它們擁有自己的視圖而且負責管理這些視圖的數據。相比之下,容器視圖控制器不擁有它的全部視圖,它的一些視圖被其它的視圖控制器管理。定義內容和容器視圖控制器的大多數步驟都是相同的,在接下來的內容裡會對此做一些討論。
對於內容視圖控制器,最常見的父類是如下這些:
-當你的容器視圖控制器的主要視圖是一個table的時候,應該明確使用UITableViewController。
-當你的容器視圖控制器的主要視圖是一個collection 視圖的時候,應該明確使用UICollectionViewController。
-對於其它的視圖控制器,使用UIViewController。
對於容器視圖控制器,使用什麼父類取決於你是打算修改一個已存在的容器類還是創建你自己的容器類。對於已經存在的容器,選擇你想要修改的那個容器類。對於新的內容視圖控制器,你通常可以子類化UIViewController。更多關於創建容器視圖控制器的額外信息,seeImplementing a Container View Controller
定義你的UI
在Xcode中,為你的視圖控制器定義可視化的UI,通常是使用storyboard 文件。盡管你也可以用編碼的方式來創建你的UI,但是storyboards是一個極好的方式,用來為不同的設備環境可視化你視圖控制器的內容和按需定制你的視圖層次結構。可視化的構建你的UI程序,可以讓你很快的改變UI界面,並且不用構建和運行你的app就可以看到你在UI上做出的改變。
圖4-1展示了一個storyboard的例子,每個矩形區域代表一個視圖控制器和與該視圖控制器相關聯的視圖。視圖控制器之間的箭頭符號代表視圖控制器之間的relationships和segues。Relationships 是一個容器視圖控制器和它的子視圖控制器之間的連接關系。在你的界面中,Segues 可以讓你在視圖控制器之間navigate。
圖4-1 一個storyboard留有一組視圖控制器和視圖
每個新建的工程都有一個main storyboard,典型地,它已經包含了一個活著多個視圖控制器。你可以添加新的視圖控制器到你的storyboard,在library 中通過拖動的方式把視圖拖到畫布中。新的視圖控制器在最開始的時候沒有與它相關聯的類,所以你必須在Identity inspector面板中給它指派一個。
使用storyboard editor 可以做如下這些事:
-添加,組織和配置視圖控制器中的視圖。
-連接outlets和actions;seeHandling User Interactions.
-在你的視圖控制器中創建relationships 和 segues ;seeUsing Segues.
-為不同的size classes 定制布局和視圖;seeBuilding an Adaptive Interface.
-添加手勢識別來在視圖上處理用戶交互; seeEvent Handling Guide for iOS.
如果在使用storyboards來創建你的界面方面你是一個新手,你可以在 Start Developing iOS APPs Today 中按照說明一步一步的來創建你的storyboard-based 界面。
處理用戶交互
一個app的responder objects 處理傳入進來的事件並且采取相應的actions來處理。盡管視圖控制器是responder objects,但是它們很少直接處理touch事件,Instead,視圖控制器處理事件的典型方法如下:
- 視圖控制器定義了action methods 來處理higher-level 事件。Action methods 響應:
--特定的動作。控制裝置和一些視圖調用一個action 方法來通知特定的交互。
--手勢識別。手勢識別調用一個action 方法來通知當前的手勢狀態。使用你的視圖控制器來處理狀態的改變或者響應完整的手勢。
- 視圖控制器observe 被系統或者是其它對象傳送過來的notifications。Notifications 通知改變,而且是視圖控制器更新狀態的一種方法。
- 視圖控制器作為其它對象的一個data source 或者 delegate。視圖控制器經常被用來管理table和collection視圖的數據。你也可以使用視圖控制器作為一個對象的delegate,例如一個CLLocationManager 對象,發送位置更新信息給它的delegate。
響應事件經常涉及到更新視圖的內容,響應事件需要擁有指向所更新的視圖的引用。視圖控制器是為視圖定義你稍後需要修改的插座變量的好地方。用下面Listing4-1中展示的語法來聲明你的插座變量屬性,在下面列表中的自定義類定義了兩個插座變量(被IBOutlet 關鍵字指定)和一個單一的動作方法(被指定為IBAction返回類型)。在storyboard中,插座變量存儲指向一個button和一個text field 的引用,同時action方法響應button按鈕中的taps。
Listing4-1 在視圖控制器類中定義outlets和actions
OBJECTIVE-C @interfaceMyViewController : UIViewController @property(weak,nonatomic)IBOutlet UIButton *myButton; @property(weak,nonatomic)IBOutlet UITextField *myTextField; -(IBAction)myButtonAction:(id)sender; @end
SWIFT classMyViewController: UIViewController { @IBOutletweak var myButton : UIButton! @IBOutletweak var myTextField : UITextField! @IBActionfunc myButtonAction(sender:id) }
在運行時展示你的視圖
Storyboards loading 和 displaying 你的視圖控制器的視圖的過程時非常簡單的。當需要的時候,UIKit 自動的從你的storyboard 文件中加載。作為加載過程的一部分,UIKit 執行下面一系列的任務:
1.用你的storyboard 文件中的信息實例化視圖。
2.連接所有的outlets 和 actions。
3.為視圖控制器的view屬性指派根視圖。
4.調用視圖控制器的awakeFromNib 方法。 當這個方法被調用時,視圖控制器的trait collection 是空的,而且視圖可能不是在它們最終的位置。
5. 調用視圖控制器的viewDidLoad 方法。 使用這個方法為你的視圖添加或者移除視圖,修改布局約束,加載數據。
在視圖控制器的視圖顯示到屏幕上之前和之後,UIKit 提供給你一些額外的機會來准備這些視圖。Specifically,UIKIt之行下面一些列任務:
1.調用視圖控制器的viewWillAppear:方法,讓它知道它的視圖將被顯示到屏幕上。
2.更新視圖的布局。
3.顯示視圖到屏幕上。
4.當視圖在屏幕上時調用viewDidAppear:方法。
當你添加,移除或者修改視圖的大小或者位置時,記得添加或者移除引用到這些視圖上的布局約束,否則你視圖層次結構的約束關系改變時,將造成UIKit 標記到髒的布局。在下一個更新循環期間,布局引起使用當前的布局約束來計算視圖的大小和位置,並將這些改變應用到視圖層次結構。
更多關於怎樣不使用storyboards創建視圖的信息,看視圖管理信息,inUIViewController Class Reference.
視圖布局管理
當你的視圖的大小和位置改變時,UIKit 為你的視圖層次結構更新布局信息。為了讓視圖配置使用自動布局,UIKit采用自動布局引擎來根據當前的約束來更新布局。UIKit 也讓其它感興趣的對象知道與它們相鄰接的布局的改變,好讓它們能夠做出響應的應答,比如被激活的presentation controller。
在布局處理期間,UIKit 通知你數個點,讓你可以執行額外的layout-related 任務。使用這些通知來修改你的布局約束或者是在布局約束被應用之前做出最後的微調。在布局處理期間,UIKit 為布局影響的視圖控制器做下面這些事:
1.根據需要更新視圖控制器的trait collection 和它的視圖;seeWhen Do Trait and Size Changes Happen?
2.調用視圖控制器的方法 viewWillLayoutSubviews。
3.調用當前UIPresentationController 對象的containerViewWillLayoutSubviews 方法。
4.調用這個視圖控制器根視圖的layoutSubviews 方法。 這個方法的默認實現事使用有效的約束來計算新的布局信息。然後這個方法穿過視圖層次調用每個子視圖的layoutSubviews 方法。
5.應用計算的布局信息到視圖上。
6.調用視圖控制器的viewDidLayoutSubviews 方法。
7.調用當前UIPresentationController 對象的containerViewDidLayoutSubviews 方法。
視圖控制器可以使用viewWillLayoutSubview 和 viewDidLayoutSubviews 方法來執行額外的更新,這樣可能會對布局過程造成影響。在布局之前,你可以添加或者移除視圖,更新視圖的大小和位置,更新約束,活著更新其它view-related 屬性。在布局之後,你可以重新加載table 數據,更新其它的視圖內容,或者是對視圖的大小和位置做出最後的調整。
下面是一些有效管理你的視圖布局的技巧:
- 使用自動布局。使用自動布局創建的約束是一種靈活和容易的方式,用來在不同尺寸的屏幕上放置你的內容。
- 充分利用頂部和底部布局向導。在這些向導上放置內容可以確保你的內容總是可見的。The top layout guide 的位置把status bar和navigation bar的高度也納入了考慮因素。同樣地,The bottom layout guide也把tab bar 或者toolbar 納入了考慮因素。
- 當你添加或者移除視圖時記得更新約束。如果你動態地添加或者移除視圖,記得更新響應的視圖約束。
- 當animating 你的視圖控制的視圖的時候,臨時移除布局約束。當你使用UIKit Core Animation animating 視圖的時候,為animations的持續時間內移除你的約束,當animations結束的時候添加它們到後台。如果在animation 期間你的視圖的大小和位置發生了改變,記得更新約束。
更多關於presentation controllers 和它們在視圖控制器架構中所扮演的角色的信息,seeThe Presentation and Transition Process
有效地管理內存
盡管分配內存的大多數方面是由你決定的,表4-1列出了類UIViewController 中最可能分配和釋放內存的方法。大多數的釋放都涉及到移除對象的強引用,為了移除對象的強引用,設置屬性和變量所指向的對象為nil。
Table 4-1 Places to allocate and deallocate memory