view控制器是通过懒加载的方式进行加载的,即用到的时候再加载。
当view视图有连线的控件时 如果view没有加载(self.view==nil) 连线是没有完成的
需要当视图需要被显示的时候才会加载视图
因此,此时视图还没有创建出来, 此时连线是没有完成的
特别注意 如果只是单纯的view 而不是view控制器 那么当加载完成后 连线是已经完成的
控制器的awakeFromNib执行时, 根视图还没有加载, 所以连线与事件连接都没有效果
当loadView执行后, 此时连线与事件连接都会生效
所以如果要操作属性一般建议在viewDidLoad中操作
loadView方法
当我们用到控制器view时,就会调用控制器view的get方法,在get方法内部,首先判断view是否已经创建,如果已存在,则直接返回存在的view,如果不存在,则调用控制器的loadView方法,在控制器没有被销毁的情况下,loadView也可能会被执行多次
如果需要重新该方法 为了自定义根视图, 因此不要执行super
注意: 将loadView理解成self.view的getter, 因此不要调用getter
以下是重写的例子
{
UIView *view = [[UIView alloc] init];
[view setBackgroundColor:[UIColor redColor]];
// 如果自定义根视图, 要将自定义的视图赋值给self.view,
//下面是setter方法 不是getter方法 不冲突
self.view = view;
};
viewDidLoad方法
当控制器的loadView方法执行完毕,view被创建成功后,就会执行viewDidLoad方法,该方法与loadView方法一样,也有可能被执行多次。在开发中,我们可能从未遇到过执行多次的情况,那什么时候会执行多次呢?
比如A控制器push出B控制器,此时,窗口显示的是B控制器的view,此时如果收到内存警告,我们一般会将A控制器中没用的变量及view销毁掉,之后当我们从B控制器pop到A控制器时,就会再次执行A控制器的loadView方法与viewDidLoad方法。
init 方法会在内存分配(alloc)完成, 初始化(init)该对象
关于控制器的实例化, 实际上是由 initWithNibname: bundle: 来实现的
Designated Initializer(指定的构造器, 由该类型的方法来实现类的实例化)
对于视图控制器而言, 使用init方法来实例化时, 本质上是调用了 initWithNibname: bundle: 来完成的, 两个参数都为nil.(从sb实例时不走该方法,因为需要读取SB文件, 解析, 还原里面保存的对象,详细请看下面3.1示例)
- 是个默认搜索机制, 先经过搜索, 确认没有与控制器关联的Nib文件后, 两个参数才是nil
- 搜索机制, 是为确认是否存在与控制器关联的Nib文件
- 搜索是否存在与控制器类名相同的Xib文件
- 搜索是否存在"控制器类名, 去掉Controller"的Xib文件
Nib是Xib的前身, Nib是可执行文件, Xib实际是XML文件 (Xib文件最多与一个控制器关联)
该XML文件会记录用户的操作, 保存起来, 在运行的时候加载该Xib文件, 解析出对应的对象
Storybord可以理解成多个Nib, 可以保存多个控制器 (里面会包含多个控制器)
IB (Interface Builder) (SB|Xib) 图形化的构造器(编辑器)
通过SB来加载控制器
1 获取Storyboard
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
2从SB当中, 加载控制器
2.1 实例化SB文件中, 初始控制器(箭头指向的那个控制器)
即需要在指定的控制器中确定 storyboard ID
ViewController *vc = [sb instantiateInitialViewController];
3实例化SB文件中, 指定的控制器 (从多个控制器当中, 根据id找到指定的控制器)
TestViewController *vc = [sb instantiateViewControllerWithIdentifier:@"TestViewController"];
3.1特别注意特别注意特别注意!
用纯代码形式而不是从NIB或SB中加载/实例化<视图>控制器时的init方法会调用下面方法
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
NSLog(@"方法");
}
return self;
}
**通过Nib(SB)来加载(视图)控制器, 会由该方进行解档 (读取SB文件, 解析, 还原里面保存的对象) **
归档 (将对象保存成数据)
解档 (数据还原成对象)
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
}
return self;
}
当加载完上面的方法 也就是从NIB或sb中加载实例化控制器对象后
Nib(SB)解档和加载的操作完成后, 会触发该方法
- (void)awakeFromNib
{
NSLog(@"SB文件的加载已经完成");
}
根视图相关的方法, 随着控制器之间的切换, 会一直触发相应的方法
** 根视图即将被显示出来 (显示之前做一些准备)**
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"根视图即将被显示出来");
}
根视图已经显示出来 (已经看到视图)
如果这个方法是由第二个视图调用 需要第一个视图已经消失后才会触发
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"根视图已经显示出来");
}
**根视图即将要消失时触发 (消失之前做一些操作) **
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
NSLog(@"根视图即将要消失时触发");
}
根视图已经消失后触发 (不是销毁)
已经消失的方法 需要下一个视图已经显示 就是下一个视图执行了视图已经显示的方法后 第一个视图的消失后触发的方法才会触发
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
NSLog(@"根视图已经消失后触发");
}
视图显示的相关方法 - 父视图相关
**该view即将移动到某个父视图上 如 self.view addsubview 方法就好调用以下方法 **
- (void)willMoveToSuperview:(UIView *)newSuperview
{
[super willMoveToSuperview:newSuperview];
NSLog(@"即将移动到某个父视图上, %@", newSuperview);
}
该view已经移动到某个父视图上
- (void)didMoveToSuperview
{
[super didMoveToSuperview];
}
视图显示的相关方法 - Window相关
该view即将被移动到某个window上
- (void)willMoveToWindow:(UIWindow *)newWindow
{
[super willMoveToWindow:newWindow];
NSLog(@"moveToWindow: %@", newWindow);
}
该view已经被移动到某个window上
- (void)didMoveToWindow
{
}
控制器的根视图是不用给frame值的
因为控制器将其改成一样大
segue连线中的属性
segue.sourceViewController —>原控制器
segue.destinationViewController —>将要跳转的控制器
sender—>触发跳转的控件
连线常见操作
// 点击了任何地方, 都会触发该方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
/*------ 手动的执行代码, 让Segue进行跳转 ------*/
// 执行指定的ID所对应的Segue (SB当中已经有该IB对应好的Segue)
[self performSegueWithIdentifier:@"VC2Second" sender:@"我的"];
}
//Segue跳转前的准备 使用连线跳转的时候会执行的方法
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(@"asdf");
}
网友评论