视图控制器
1. 为什么要有视图控制器
- 我们开发中,可能会遇到某个界面比较复杂,要进行多个界面的切换,如果把这些界面切换全都放在该界面中,控制器代码非常臃肿不说,控制起来也比较麻烦,这个时候我建议用不同的控制器来表示不同的界面,然后将这些界面通过addChildViewController添加到控制器的子控制器中,然后通过系统提供的方法进行切换。
2. 视图控制器的生命周期
- 当一个视图控制器被创建,并在屏幕上显示的时候。 代码的执行顺序
```c
1、 alloc 创建对象,分配空间
2、init (initWithNibName) 初始化对象,初始化数据
3、loadView 从nib载入视图 ,通常这 一步不需要去干涉。除非你没有使用xib文件创建视图
4、viewDidLoad 载入完成,可以进行自定义数据以及动态创建其他控件
5、viewWillAppear 视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了
6、viewDidAppear 视图已在屏幕上渲染完成
当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反
1、viewWillDisappear 视图将被从屏幕上移除之前执行
2、viewDidDisappear 视图已经被从屏幕上移除,用户看不到这个视图了
3、deainit 视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放
```
* 当我们创建一个UIViewController类的对象时,通常系统会生成几个默认的方法,这些方法大多与视图的调用有关,但是在视图调用时,这些方法的调用顺序如何,需要整理下。
通常上述方法包括如下几种,这些方法都是UIViewController类的方法:
```c
-(void)viewDidLoad;
-(void)viewDidUnload;
-(void)viewWillAppear:(BOOL)animated;
-(void)viewDidAppear:(BOOL)animated;
-(void)viewWillDisappear:(BOOL)animated;
-(void)viewDidDisappear:(BOOL)animated;
```
3. 生命周期的每个方法干什么用
下面介绍下APP在运行时的调用顺序。
-
1)- (void)viewDidLoad;
一个APP在载入时会先通过调用loadView方法或者载入IB中创建的 初始界面的方法,将视图载入到内存中。然后会调用viewDidLoad方法来进行进一步的设置。通常,我们对于各种初始数据的载入,初始设定等很多内容,都会在这个方法中实现,所以这个方法是一个很常用,很重要的方法。
但是要注意,这个方法只会在APP刚开始加载的时候调用一次,以后都不会再调用它了,所以只能用来做初始设置。 - (void)viewDidUnload;
在内存足够的情况下,软件的视图通常会一直保存在内存中,但是如果内存不够,一些没有正在显示的viewcontroller就会收到内存不够的警告,然后就会释放自己拥有的视图,以达到释放内存的目的。但是系统只会释放内存,并不会释放对象的所有权,所以通常我们需要在这里将不需要在内存中保留的对象释放所有权,也就是将其指针置为nil。
这个方法通常并不会在视图变换的时候被调用,而只会在系统退出或者收到内存警告的时候才会被调用。但是由于我们需要保证在收到内存警告的时候能够对其作出反应,所以这个方法通常我们都需要去实现。
另外,即使在设备上按了Home键之后,系统也不一定会调用这个方法,因为IOS4之后,系统允许将APP在后台挂起,并将其继续滞留在内存中,因此,viewcontroller并不会调用这个方法来清除内存。
- (void)viewDidUnload;
-
3)- (void)viewWillAppear:(BOOL)animated;
系统在载入所有数据后,将会在屏幕上显示视图,这时会先调用这个方法。通常我们会利用这个方法,对即将显示的视图做进一步的设置。例如,我们可以利用这个方法来设置设备不同方向时该如何显示。
另外一方面,当APP有多个视图时,在视图间切换时,并不会再次载入viewDidLoad方法,所以如果在调入视图时,需要对数据做更新,就只能在这个方法内实现了。所以这个方法也非常常用。 - (void)viewDidAppear:(BOOL)animated;
有时候,由于一些特殊的原因,我们不能在viewWillApper方法里,对视图进行更新。那么可以重写这个方法,在这里对正在显示的视图进行进一步的设置。
- (void)viewDidAppear:(BOOL)animated;
- (void)viewWillDisappear:(BOOL)animated;
在视图变换时,当前视图在即将被移除、或者被覆盖时,会调用这个方法进行一些善后的处理和设置。
由于在IOS4之后,系统允许将APP在后台挂起,所以在按了Home键之后,系统并不会调用这个方法,因为就这个APP本身而言,APP显示的view,仍是挂起时候的view,所以并不会调用这个方法。
- (void)viewWillDisappear:(BOOL)animated;
- (void)viewDidDisappear:(BOOL)animated;
我们可以重写这个方法,对已经消失,或者被覆盖,或者已经隐藏了 的视图做一些其他操作。
- (void)viewDidDisappear:(BOOL)animated;
4.模态推出
//模态推出下一个界面,一般用于注册
let vc = SecondViewController()
//1.要推出的下一个控制器
//2.是否有动画
//3.推出完成之后回掉
self.present(vc,animated: true){
}
5. view是懒加载的
6. 属性传值
- 第二个视图控制器如何获取第一个视图控制器的部分信息
例如 :第二个界面中的lable显示第一个界面textField中的文本
这就需要用到属性传值 - 属性传值就好比是一个渴了的人走到茶水间,向管理员要了一个杯子,然后又让其为自己的杯子倒满水的过程。当然,在编码中情况会更为复杂,因为一个项目工程中,每个类都可能会是管理员,也可能是口渴者,或者二者皆是,而其中又会有很多的杯子(属性)。但如果把这些拿出来一一类比,其实原理都是一样简单。
• 传值者->茶水间管理员,负责管理各种饮品
• 接收者->到茶水间找水喝的人
• 属性->茶水间的杯子
• 值->水
7. 实例
实现点击按钮,进入下一个视图,再点击返回上一个视图
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()
//替换当前控制器的view
// let imageV = UIImageView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
// self.view = imageV
}
//加载相关资源
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor=UIColor.red
//视图控制器
//UIControl子类
//手势
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) {
//模态推出下一个界面,一般用于注册
let vc = SecondViewController()
//1.要推出的下一个控制器
//2.是否有动画
//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 {
}
//接收到内存警告
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) {
//从前页面回收回去
self.dismiss(animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
网友评论