視圖控制器
1. 為什么要有視圖控制器
- 我們開(kāi)發(fā)中,可能會(huì)遇到某個(gè)界面比較復(fù)雜,要進(jìn)行多個(gè)界面的切換佛掖,如果把這些界面切換全都放在該界面中,控制器代碼非常臃腫不說(shuō)涌庭,控制起來(lái)也比較麻煩芥被,這個(gè)時(shí)候我建議用不同的控制器來(lái)表示不同的界面,然后將這些界面通過(guò)addChildViewController添加到控制器的子控制器中坐榆,然后通過(guò)系統(tǒng)提供的方法進(jìn)行切換拴魄。
2. 視圖控制器的生命周期
- 當(dāng)一個(gè)視圖控制器被創(chuàng)建,并在屏幕上顯示的時(shí)候席镀。 代碼的執(zhí)行順序
```c
1匹中、 alloc 創(chuàng)建對(duì)象,分配空間
2愉昆、init (initWithNibName) 初始化對(duì)象职员,初始化數(shù)據(jù)
3、loadView 從nib載入視圖 跛溉,通常這 一步不需要去干涉。除非你沒(méi)有使用xib文件創(chuàng)建視圖
4扮授、viewDidLoad 載入完成芳室,可以進(jìn)行自定義數(shù)據(jù)以及動(dòng)態(tài)創(chuàng)建其他控件
5、viewWillAppear 視圖將出現(xiàn)在屏幕之前刹勃,馬上這個(gè)視圖就會(huì)被展現(xiàn)在屏幕上了
6堪侯、viewDidAppear 視圖已在屏幕上渲染完成
當(dāng)一個(gè)視圖被移除屏幕并且銷毀的時(shí)候的執(zhí)行順序,這個(gè)順序差不多和上面的相反
1荔仁、viewWillDisappear 視圖將被從屏幕上移除之前執(zhí)行
2伍宦、viewDidDisappear 視圖已經(jīng)被從屏幕上移除,用戶看不到這個(gè)視圖了
3乏梁、deainit 視圖被銷毀次洼,此處需要對(duì)你在init和viewDidLoad中創(chuàng)建的對(duì)象進(jìn)行釋放
```
* 當(dāng)我們創(chuàng)建一個(gè)UIViewController類的對(duì)象時(shí),通常系統(tǒng)會(huì)生成幾個(gè)默認(rèn)的方法遇骑,這些方法大多與視圖的調(diào)用有關(guān)卖毁,但是在視圖調(diào)用時(shí),這些方法的調(diào)用順序如何落萎,需要整理下亥啦。
通常上述方法包括如下幾種炭剪,這些方法都是UIViewController類的方法:
```c
-(void)viewDidLoad;
-(void)viewDidUnload翔脱;
-(void)viewWillAppear:(BOOL)animated奴拦;
-(void)viewDidAppear:(BOOL)animated;
-(void)viewWillDisappear:(BOOL)animated届吁;
-(void)viewDidDisappear:(BOOL)animated错妖;
```
3. 生命周期的每個(gè)方法干什么用
下面介紹下APP在運(yùn)行時(shí)的調(diào)用順序。
1)- (void)viewDidLoad瓷产;
一個(gè)APP在載入時(shí)會(huì)先通過(guò)調(diào)用loadView方法或者載入IB中創(chuàng)建的 初始界面的方法站玄,將視圖載入到內(nèi)存中。然后會(huì)調(diào)用viewDidLoad方法來(lái)進(jìn)行進(jìn)一步的設(shè)置濒旦。通常株旷,我們對(duì)于各種初始數(shù)據(jù)的載入,初始設(shè)定等很多內(nèi)容尔邓,都會(huì)在這個(gè)方法中實(shí)現(xiàn)晾剖,所以這個(gè)方法是一個(gè)很常用,很重要的方法梯嗽。
但是要注意齿尽,這個(gè)方法只會(huì)在APP剛開(kāi)始加載的時(shí)候調(diào)用一次,以后都不會(huì)再調(diào)用它了灯节,所以只能用來(lái)做初始設(shè)置循头。- (void)viewDidUnload;
在內(nèi)存足夠的情況下,軟件的視圖通常會(huì)一直保存在內(nèi)存中炎疆,但是如果內(nèi)存不夠卡骂,一些沒(méi)有正在顯示的viewcontroller就會(huì)收到內(nèi)存不夠的警告,然后就會(huì)釋放自己擁有的視圖形入,以達(dá)到釋放內(nèi)存的目的全跨。但是系統(tǒng)只會(huì)釋放內(nèi)存,并不會(huì)釋放對(duì)象的所有權(quán)亿遂,所以通常我們需要在這里將不需要在內(nèi)存中保留的對(duì)象釋放所有權(quán)浓若,也就是將其指針置為nil。
這個(gè)方法通常并不會(huì)在視圖變換的時(shí)候被調(diào)用蛇数,而只會(huì)在系統(tǒng)退出或者收到內(nèi)存警告的時(shí)候才會(huì)被調(diào)用挪钓。但是由于我們需要保證在收到內(nèi)存警告的時(shí)候能夠?qū)ζ渥鞒龇磻?yīng),所以這個(gè)方法通常我們都需要去實(shí)現(xiàn)苞慢。
另外诵原,即使在設(shè)備上按了Home鍵之后,系統(tǒng)也不一定會(huì)調(diào)用這個(gè)方法,因?yàn)镮OS4之后绍赛,系統(tǒng)允許將APP在后臺(tái)掛起蔓纠,并將其繼續(xù)滯留在內(nèi)存中,因此吗蚌,viewcontroller并不會(huì)調(diào)用這個(gè)方法來(lái)清除內(nèi)存腿倚。
- (void)viewDidUnload;
3)- (void)viewWillAppear:(BOOL)animated;
系統(tǒng)在載入所有數(shù)據(jù)后,將會(huì)在屏幕上顯示視圖蚯妇,這時(shí)會(huì)先調(diào)用這個(gè)方法敷燎。通常我們會(huì)利用這個(gè)方法,對(duì)即將顯示的視圖做進(jìn)一步的設(shè)置箩言。例如硬贯,我們可以利用這個(gè)方法來(lái)設(shè)置設(shè)備不同方向時(shí)該如何顯示。
另外一方面陨收,當(dāng)APP有多個(gè)視圖時(shí)饭豹,在視圖間切換時(shí),并不會(huì)再次載入viewDidLoad方法务漩,所以如果在調(diào)入視圖時(shí)拄衰,需要對(duì)數(shù)據(jù)做更新,就只能在這個(gè)方法內(nèi)實(shí)現(xiàn)了饵骨。所以這個(gè)方法也非常常用翘悉。- (void)viewDidAppear:(BOOL)animated;
有時(shí)候居触,由于一些特殊的原因妖混,我們不能在viewWillApper方法里,對(duì)視圖進(jìn)行更新轮洋。那么可以重寫(xiě)這個(gè)方法源葫,在這里對(duì)正在顯示的視圖進(jìn)行進(jìn)一步的設(shè)置。
- (void)viewDidAppear:(BOOL)animated;
- (void)viewWillDisappear:(BOOL)animated砖瞧;
在視圖變換時(shí),當(dāng)前視圖在即將被移除嚷狞、或者被覆蓋時(shí)块促,會(huì)調(diào)用這個(gè)方法進(jìn)行一些善后的處理和設(shè)置。
由于在IOS4之后床未,系統(tǒng)允許將APP在后臺(tái)掛起竭翠,所以在按了Home鍵之后,系統(tǒng)并不會(huì)調(diào)用這個(gè)方法薇搁,因?yàn)榫瓦@個(gè)APP本身而言斋扰,APP顯示的view,仍是掛起時(shí)候的view,所以并不會(huì)調(diào)用這個(gè)方法传货。
- (void)viewWillDisappear:(BOOL)animated砖瞧;
- (void)viewDidDisappear:(BOOL)animated屎鳍;
我們可以重寫(xiě)這個(gè)方法,對(duì)已經(jīng)消失问裕,或者被覆蓋逮壁,或者已經(jīng)隱藏了 的視圖做一些其他操作。
- (void)viewDidDisappear:(BOOL)animated屎鳍;
4.模態(tài)推出
//模態(tài)推出下一個(gè)界面粮宛,一般用于注冊(cè)
let vc = SecondViewController()
//1.要推出的下一個(gè)控制器
//2.是否有動(dòng)畫(huà)
//3.推出完成之后回掉
self.present(vc,animated: true){
}
5. view是懶加載的
6. 屬性傳值
- 第二個(gè)視圖控制器如何獲取第一個(gè)視圖控制器的部分信息
例如 :第二個(gè)界面中的lable顯示第一個(gè)界面textField中的文本
這就需要用到屬性傳值 - 屬性傳值就好比是一個(gè)渴了的人走到茶水間窥淆,向管理員要了一個(gè)杯子,然后又讓其為自己的杯子倒?jié)M水的過(guò)程巍杈。當(dāng)然忧饭,在編碼中情況會(huì)更為復(fù)雜,因?yàn)橐粋€(gè)項(xiàng)目工程中筷畦,每個(gè)類都可能會(huì)是管理員词裤,也可能是口渴者,或者二者皆是汁咏,而其中又會(huì)有很多的杯子(屬性)亚斋。但如果把這些拿出來(lái)一一類比,其實(shí)原理都是一樣簡(jiǎn)單攘滩。
? 傳值者->茶水間管理員帅刊,負(fù)責(zé)管理各種飲品
? 接收者->到茶水間找水喝的人
? 屬性->茶水間的杯子
? 值->水
7. 實(shí)例
實(shí)現(xiàn)點(diǎn)擊按鈕,進(jìn)入下一個(gè)視圖漂问,再點(diǎn)擊返回上一個(gè)視圖
import UIKit
class ViewController: UIViewController {
// override init(nibName nibNameOrNil : String? ,bundle nibBundleOrNil:Bundle?) {
// //1.加載的xib文件
// //2.bundle
// super.init(nibName: nibNameOrNil , bundle: nibBundleOrNil)
//
// }
// required init?(coder aDecoder:NSCoder){
// fatalError("init(coder:) has not been implemented")
// }
//加載view
override func loadView() {
super.loadView()
//替換當(dāng)前控制器的view
// let imageV = UIImageView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
// self.view = imageV
}
//加載相關(guān)資源
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor=UIColor.red
//視圖控制器
//UIControl子類
//手勢(shì)
let btn = UIButton(type: .system)
btn.frame=CGRect(x: 100, y: 100, width: 50, height: 40)
btn.addTarget(self, action: #selector(btnAction(btn:)), for: .touchUpInside)
btn.setTitle("登錄", for: .normal)
self.view.addSubview(btn)
}
func btnAction(btn:UIButton) {
//模態(tài)推出下一個(gè)界面赖瞒,一般用于注冊(cè)
let vc = SecondViewController()
//1.要推出的下一個(gè)控制器
//2.是否有動(dòng)畫(huà)
//3.推出完成之后回掉
self.present(vc,animated: true){
}
}
//視圖將要顯示在頻幕上
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
//顯示在頻幕上
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
//視圖將要從頻幕上消失
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}
// 控制器被銷毀
deinit {
}
//接收到內(nèi)存警告
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
import UIKit
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor=UIColor.white
let btn = UIButton(type: .system)
btn.frame=CGRect(x: 100, y: 100, width: 50, height: 40)
btn.addTarget(self, action: #selector(btnAction(btn:)), for: .touchUpInside)
btn.setTitle("登錄", for: .normal)
self.view.addSubview(btn)
}
func btnAction(btn:UIButton) {
//從前頁(yè)面回收回去
self.dismiss(animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}