控制器生命周期的执行顺序示意图
1 init函数(init;initWithFrame;initWithCoder;等)--初始化
2 awakeFromNib--在loadView之前的工作放在这里
3 viewDidLoad--注意,一个ViewController一个生命周期内这个函数只会调用一次
4 viewWillAppear -- view将要出现,每次View消失再出现都会调用
5 viewWillLayoutSubviews--简要对子试图进行布局
6 viewDidLayoutSubivews--完成对子试图布局
7 viewDidAppear--视图将要出现在屏幕上
---上述代码不含部分
8 viewWillDisappear--View将要消失
9 viewDidDisappear--View已经消失
- 控制器的生命周期方法
// view加载完毕
- (void)viewDidLoad
// view即将显示到window上
- (void)viewWillAppear:(BOOL)animated
// view显示完毕(已经显示窗口)
- (void)viewDidAppear:(BOOL)animated
// view即将从window上移除(即将看不见)
- (void)viewWillDisappear:(BOOL)animated
// view从window上完全移除(完全看不见)
- (void)viewDidDisappear:(BOOL)animated
// view即将销毁的时候调用
- (void)viewWillUnload
// view销毁完毕的时候调用
- (void)viewDidUnload
// 当接收到内存警告的时候
- (void)didReceiveMemoryWarning
// 通过一个frame来初始化一个UI控件
- (id)initWithFrame:(CGRect)frame;
1. 演示导航控制器根控制器View的生命周期(viewDidLoad这些view开头的,称为生命周期方法)
• 通过view的生命周期方法,就知道控制器的view是懒加载的,导航控制器有2个子控制器,先会加载第一个子控制器的view,当Push 第二个的时候,才去加载第二个控制器的view
2. didReceiveMemoryWarning,当控制器接收内存警告的时候调用
3. 内存警告传递过程:手机内存不足产生事件->通知应用程序->调用应用程序代理方法->把事件传递给窗口->窗口传给控制器->调用控制器 内存警告的方法。
4. 当控制器接收内容警告,会销毁没有显示的控制器的view。
5. 调用viewWillUnload,viewDidUnload,销毁控制器的view
6. viewDidUnload里面一般清空显示在view里面的数据,演示非arc开发
• 为什么要清空显示view的数据:展示数据的view都不存在了,这些数据也就没有用处了,因为数据主要是用来展示在view上的。
• 建议使用nil,清空数据,在非arc和arc都通用。arc是不能使用release,而且非arc,self.datas = nil;做的事情更多。
7. didReceiveMemoryWarning会导致viewDidLoad重新调用。
当收到内存警告,导航控制器的子控制器的view有可能被干掉,他如果没有显示的话,当下次使用这个控制器的时候就会调用。
8. 控制器View加载流程
视图控制器的切换方式
1. Tabbar选项卡:以UITabbarController为容器,以平行的方式是管理子视图控制器
2. Push推送:以UINavigationController为容器,以栈的形式管理子视图控制器
3. Modal模态:以模态窗口的方式显示新的视图控制器,新视图控制器关闭前,用户无法与原控制器进行交互 在ipad里面modal窗口要比背景的窗口要小
控制器的数据传递
- 控制器的数据传递
• 控制器之间的数据传递主要有2种情况:顺传和逆传
a. 顺传
§ 控制器的跳转方向: A -> B
§ 数据的传递方向: A -> B
§ 数据的传递方式: 在A的prepareForSegue:sender:
方法中根据segue
参数取得destinationViewController
, 也就是控制器B,直接给控制器B传递数据
§ 在B的viewDidLoad方法中取得数据,或者利用setter方法,设置界面上的UI控件
a. 代码实现:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *vc = segue.destinationViewController;
//判断当前对象,是否是给定类型的实例,或给定类型子类的实例
if ([vc isKindOfClass:[CZAddContactViewController class]])
{
CZAddContactViewController *addVC = (CZAddContactViewController *)vc;
addVC.delegate = self;
} else if ([vc isKindOfClass:[CZEditContactViewController class]]) {
//传递当前cell的数据 给修改联系人控制器
CZEditContactViewController *editVC = (CZEditContactViewController *)vc;
//获取当前tableView中选中的行号
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; editVC.contact = self.contacts[indexPath.row];
} }
b. 逆传
§ 控制器的跳转方向: A -> B
§ 数据的传递方向: B -> A
§ 数据的传递方式: 让A成为B的代理,在B中调用A的代理方法,通过代理方法的参数传递数据给A
2. 参数传递
假设用户名输入“kenshincui”,密码输入“123”就认为登录成功,否则登录失败。同时登录成功之后在主视图控制器中显示用户名并且登录按钮变成“注销”。要实现这个功能主要的问题就是如何把登录后的用户名信息传递到主界面?由此引出一个问题:多视图参数传递。
在iOS开发中常用的参数传递有以下几种方法:
1. 采用代理模式
2. 采用iOS消息机制
3. 通过NSDefault存储(或者文件、数据库存储等)
4. 通过AppDelegate定义全局变量(或者使用UIApplication、定义一个单例类等)
5. 通过控制器属性传递
今天我们主要采用第一种方式进行数据传递,这在iOS开发中也是最常见的一种多视图传参方式。使用代理方式传递参数的步骤如下:
1.定义协议,协议中定义好传参时所需要的方法
2.目标视图控制器定义一个代理对象
3.源视图控制器实现协议并在初始化目标控制器时指定目标控制器的代理为其自身
4.需要传参的时候在目标窗口调用代理的协议方法