當(dāng)你使用UIViewController的自定義子類來展示你應(yīng)用內(nèi)容秕脓。大多數(shù)自定義視圖控制器是內(nèi)容視圖控制器队魏,他們有自己的視圖并負(fù)責(zé)管理這些視圖中的數(shù)據(jù)室囊。相比之下泼橘,容器視圖控制器并不擁有所有的視圖饲宿,一些視圖是由其他視圖控制器管理厦酬。大多數(shù)定義內(nèi)容和容器視圖控制器的步驟是一樣的,這些將在下面幾節(jié)中討論瘫想。
內(nèi)容視圖控制器仗阅,最常見的父類如下:
·使用UITableViewController,尤其是當(dāng)你的視圖控制器的主要視圖是表国夜。
·使用UICollectionViewController减噪,尤其是當(dāng)你的視圖控制器的主要視圖是一個集合視圖。
·其他所有的視圖控制器使用UIViewController车吹。
對于容器視圖控制器筹裕,父類取決于是否修改一個已經(jīng)存在的容器類或者創(chuàng)建你自己的。對于現(xiàn)有容器礼搁,選擇你想要修改的視圖控制器類饶碘。對于新的容器視圖控制器,通常繼承UIViewController馒吴。關(guān)于創(chuàng)建容器視圖控制器的更多信息扎运,參見實(shí)現(xiàn)容器視圖控制器(Implementing a Container View Controller)。
定義UI
為視圖控制器定義UI通常使用Xcode中的storyboard饮戳。雖然也可以通過編程創(chuàng)建UI豪治,但storyboard是一個非常好的方法來可視化視圖控制器的內(nèi)容并在不同的環(huán)境(如果需要)定制你的視圖層級。構(gòu)建視覺UI可以讓你快速的改變并讓你看到結(jié)果扯罐,而無需構(gòu)建和運(yùn)行應(yīng)用负拟。
圖4-1展示了storyboard的例子。每個矩形區(qū)域代表一個視圖控制器和其相關(guān)的視圖歹河。視圖控制器之間的箭頭是視圖間關(guān)系和聯(lián)線掩浙。Relationships連接一個容器視圖控制到它的子視圖控制器。Segues讓你在界面視圖控制器之間導(dǎo)航秸歧。
每個新項(xiàng)目都有一個主storyboard厨姚,通常包含一個或多個視圖控制器。通過拖放它們到畫布上键菱,可以添加新的視圖控制器到storyboard谬墙。新視圖控制器最初沒有相關(guān)的類成肘,你必須使用標(biāo)示符賦值蠢琳。
使用storyboard編輯器來完成以下操作:
·為一個視圖控制器添加昌简、整理并配置視圖沦疾。
·連接outlet和action,參見處理用戶交互(Handling User Interactions)造虎。
·創(chuàng)建視圖控制器之間的關(guān)系和聯(lián)線傅蹂,參見使用segues(Using Segues)。
·為不同的size類定義布局和視圖累奈,參見構(gòu)建自適應(yīng)界面(Building an Adaptive Interface)贬派。
·添加手勢識別器來處理用戶交互視圖,參見iOS事件處理指南(Event Handling Guide for iOS)澎媒。如果你是使用storyboard來建立你的界面搞乏,你可以在iOS應(yīng)用開發(fā)中找到循序漸進(jìn)的指示來創(chuàng)建基于storyboard的界面。
處理用戶交互
應(yīng)用的響應(yīng)者對象處理傳入的事件并采取適當(dāng)?shù)膭幼鹘渑km然視圖控制器是響應(yīng)者對象请敦,但他們很少直接處理觸摸事件。相反储玫,視圖控制器通常以以下方式處理事件侍筛。
·視圖控制器為處理高級別事件定義動作方法。動作方法響應(yīng):
1.指定動作撒穷∠灰控制器和一些視圖調(diào)用一個動作方法來響應(yīng)特定交互。
2.手勢識別器端礼。手勢識別器調(diào)用一個動作方法來響應(yīng)當(dāng)前手勢狀態(tài)禽笑。使用視圖控制器來處理狀態(tài)變化或響應(yīng)完成的手勢。
·視圖控制器觀察系統(tǒng)或其他對象發(fā)送的通知蛤奥。通知報告變化佳镜,同時也是視圖控制器更新狀態(tài)的一種方式。
·視圖控制器作為其他對象的數(shù)據(jù)源或代理凡桥。視圖控制器通常用于管理表的數(shù)據(jù)蟀伸、集合視圖的數(shù)據(jù)。你可以使用它們作為對象的代理缅刽,例如CLLocationManager對象啊掏,發(fā)送更新的位置值到它的代理。
響應(yīng)事件通常包括更新視圖的內(nèi)容衰猛,這需要有這些視圖的引用脖律。視圖控制器可以定義任何視圖的outlet。使用列表4-1中的語法來聲明你的outlet屬性腕侄。列表中的自定義類定義了兩個outlet(IBOutlet指定的關(guān)鍵字)和一個動作方法(IBOutlet指定的返回類型)。雖然動作方法響應(yīng)按鈕點(diǎn)擊事件,Outlet存儲了storyboard中按鈕和文本框中的引用冕杠。
列表4-1在視圖控制器類中定義outlet和動作微姊。
OBJECTIVE-C
<pre><code>
@interface
MyViewController:UIViewController
@property(weak,nonatomic)IBOutletUIButton*myButton;
@property(weak,nonatomic)IBOutletUITextField*myTextField;
-(IBAction)myButtonAction:(id)sender;
@end
</pre></code>
SWIFT
<pre><code>
classMyViewController:UIViewController{
@IBOutletweakvarmyButton:UIButton!
@IBOutletweakvarmyTextField:UITextField!
@IBActionfuncmyButtonAction(sender:id)
}
</pre></code>
在storyboard中,記得連接視圖控制器的outlet和動作到相應(yīng)的視圖分预。連接storyboard中的outlet和動作確保黨視圖加載時他們已配置好兢交。更多關(guān)于如何在IB中創(chuàng)建outlet和動作連接的方法,參見IB連接幫助(Interface Builder Connections Help)笼痹。更多關(guān)于如何處理應(yīng)用中事件配喳,參見iOS事件處理指南(Event Handling Guide for iOS)。
在運(yùn)行時顯示視圖
Storyboard使加載和顯示視圖控制器的視圖變得簡單凳干。UIKit自動從storyboard加載視圖晴裹。隨著加載過程,UIKit執(zhí)行以下的任務(wù)序列:
1.使用storyboard文件中的信息實(shí)例化視圖救赐。
2.連接所有outlet和動作涧团。
3.指定根視圖為視圖控制器的視圖屬性。
4.調(diào)用視圖控制器的awakeFromNib方法经磅。
當(dāng)調(diào)用此方法泌绣,視圖控制器的特征集合為空,視圖可能不在最后的位置预厌。
5.調(diào)用視圖控制器的viewDidLoad方法阿迈。
使用該方法添加或刪除視圖,修改布局約束轧叽,加載視圖數(shù)據(jù)苗沧。
在屏幕上顯示視圖控制器的視圖前,UIKit提供額外的機(jī)會準(zhǔn)備這些視圖犹芹,之后顯示在屏幕上崎页。具體說來,UIKit執(zhí)行以下任務(wù)序列:
1.調(diào)用視圖控制器的viewWillAppear:方法讓它知道視圖將出現(xiàn)在屏幕上腰埂。
2.更新視圖布局飒焦。
3.在屏幕上顯示視圖。
4.當(dāng)視圖在屏幕上調(diào)用viewDidAppear:方法屿笼。
當(dāng)添加牺荠、刪除或修改視圖的大小或位置,記得添加和刪除用于這些視圖的約束驴一。修改視圖層級的布局相關(guān)變更會導(dǎo)致UIKit布局混亂休雌。在接下來的更新周期,布局引擎計算視圖的大小和位置肝断,使用當(dāng)前布局約束并將這些更改應(yīng)用到視圖層級結(jié)構(gòu)杈曲。
關(guān)于如何創(chuàng)建視圖而不使用storyboard的更多信息驰凛,參見UIViewController類引用(UIViewController Class Reference)中的視圖管理信息。
管理視圖布局
當(dāng)視圖的大小和位置發(fā)生變化担扑,UIKit更新視圖層級的布局信息恰响。對于使用自動布局的視圖,UIKit使用自動布局引擎并根據(jù)當(dāng)前約束使用它更新布局涌献。UIKit還允許其他對象胚宦,例如活動展示控制器,知道布局變化燕垃,這樣它們可以做相應(yīng)的回應(yīng)枢劝。
在布局過程中,在幾個點(diǎn)上UIKit發(fā)出通知卜壕,這樣可以執(zhí)行額外的布局相關(guān)任務(wù)您旁。使用這些通知來修改布局約束或者在布局約束應(yīng)用后做最后的布局調(diào)整。在布局過程中印叁,UIKit為每個受影響的視圖控制器做如下任務(wù):
1.根據(jù)需要被冒,更新視圖控制器和視圖的特征集合,參見特征和大小變更的時間(When Do Trait and Size Changes Happen)
2.調(diào)用視圖控制器的viewWillLayoutSubviews方法轮蜕。
3.調(diào)用當(dāng)前UIPresentationController對象的containerViewWillLayoutSubviews方法昨悼。
4.調(diào)用視圖控制器的根視圖的layoutSubviews方法。
該方法默認(rèn)使用可用約束實(shí)現(xiàn)計算新布局信息跃洛。該方法遍歷視圖層級并為每個子視圖調(diào)用layoutSubviews率触。
5.運(yùn)用計算好的布局信息到視圖。
6.調(diào)用視圖控制器的viewDidLayoutSubviews方法汇竭。
7.調(diào)用當(dāng)前UIPresentationController對象的containerViewDidLayoutSubviews方法葱蝗。
視圖控制器可以使用viewWillLayoutSubviews和viewDidLayoutSubviews方法執(zhí)行額外更新,這些更新可能會影響布局過程细燎。布局之前两曼,你可以添加或刪除視圖,更新視圖的大小和位置玻驻,更新約束悼凑,或者更新其他視圖相關(guān)屬性。布局之后璧瞬,可能重新加載表數(shù)據(jù)户辫,更新其他視圖的內(nèi)容,或者最后調(diào)整視圖大小和位置嗤锉。
這里有些小提示可以有效的管理布局:
·使用自動布局渔欢。使用自動布局創(chuàng)建的約束是一種靈活和簡單的方式在不同屏幕尺寸上定位你的內(nèi)容。
·利用頂部和底部布局參考線瘟忱。內(nèi)容布局中的參考線確保內(nèi)容總是可見的奥额。頂部位置的布局參考線把狀態(tài)欄和導(dǎo)航欄的高度考慮在內(nèi)苫幢。同樣的,底部位置的布局參考線把tab欄或工具欄的高度考慮在內(nèi)披坏。
·當(dāng)添加或刪除視圖時記得更新約束态坦。如果動態(tài)添加或刪除視圖,記得更新相應(yīng)的約束棒拂。
·當(dāng)視圖控制器的視圖在動畫時,暫時刪除約束玫氢。當(dāng)使用UIKit核心動畫完成視圖動畫帚屉,在動畫期間刪除約束并在動畫完成時添加約束。如果在動畫期間視圖的位置或尺寸改變漾峡,記得更新約束攻旦。
關(guān)于顯示控制器和視圖控制器結(jié)構(gòu)中的作用信息,參見present和transit過程(The Presentation and Transition Process)生逸。
有效管理內(nèi)存
盡管大多數(shù)方面的內(nèi)存分配由你來決定牢屋,表4-1列出了的UIViewControll方法,這些方法最有可能出現(xiàn)分配或釋放內(nèi)存槽袄。大多數(shù)回收涉及刪除對象的強(qiáng)引用烙无。刪除對象的強(qiáng)引用,設(shè)置指向改對象的屬性和變量為nil遍尺。
任務(wù) | 方法 | 討論 |
---|---|---|
分配視圖控制器所需的關(guān)鍵數(shù)據(jù)結(jié)構(gòu) | Initialization methods | 自定義initialization方法(無論是否名為init或其他)總是負(fù)責(zé)把視圖控制器對象放到一個已知狀態(tài)截酷。使用這些方法來分配任何數(shù)據(jù)結(jié)構(gòu)以確保正確的操作。 |
分配或加載視圖中顯示的數(shù)據(jù) | viewDidLoad | 使用viewDidLoad方法加載要顯示的任何數(shù)據(jù)對象乾戏。調(diào)用此方法時迂苛,保證視圖對象存在并且處于已知狀態(tài)。 |
響應(yīng)低內(nèi)存通知 | didReceiveMemoryWarning | 使用該方法釋放視圖控制器所有相關(guān)對象鼓择。盡量釋放內(nèi)存三幻。 |
釋放視圖控制器的關(guān)鍵數(shù)據(jù)結(jié)構(gòu) | dealloc | 覆蓋該方法在最后清理視圖控制器類。系統(tǒng)自動釋放實(shí)例變量對象及類屬性呐能,所以你不需要顯示的釋放它們念搬。 |
表4-1進(jìn)行分配和釋放內(nèi)存的地方