粗略总结一下iOS中加载一个UIViewController的几
iOS中要在一个UIViewController(比如说A1)中加载或者说推出下一个UIViewController(比如说A2)的常用方法有三种:pushViewController,presentViewController和addChildViewController。粗略总结一下,以后持续完善。
1.pushViewController
这应该是最常用的方法了,而且简单快捷,且支持一个从左到右的过场动画。但是前提是前一个UIViewController,A1的navigationController不能为空,因为
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
这个方法是属于UINavigationController的方法。这个不用多说。
A1 push了A2后,做了什么操作呢?我推测大概有以下几个动作:
a.A2.navigationController = A1.navigationController,
由于是UINavigationController统一管理push的新ViewController,而且A2的navigationController属性自动被赋值了。也就是说被push的ViewController可以直接push下一层ViewController,所有新的ViewController都是通过rootViewController管理的,而且是栈的形式管理。
b.A2被push之后,A2.view的父view并不是A1的view。
A2.view的层级关系如下图:
每一次push后,被push的ViewCtronller都是类似结构。输出每一层ViewController的UIViewControllerWrapperView指针,发现它们是同一个指针。也就是说每一个被push的ViewController.view都被UINavigationController的统一addSubviewd到UIViewControllerWrapperView中。
通过查看UIViewControllerWrapperView的subviews发现了一个神奇的事情,每次push一个新的ViewController,UIViewControllerWrapperView的subviews都只有最新的ViewController的view,不管你push了多少次!比如,我在A1上push了A2,在A2上又push了A3。UIViewControllerWrapperView的subviews中只有A3的view没有A2的view。
以下只是个人推测,感兴趣的可以看看:我推测是iOS在push了A3之后,把A2的ViewController的view缓存起来了,然后addsubview A3的view。待A3被pop之后,再把A2的view从缓存addsubview到UIViewControllerWrapperView中。进一步推测的话,是不是viewController的view被addSubView到UIViewControllerWrapperView中,才调用viewWillAppear等一系列函数,被移除的时候调用viewWillDisappear。
2.presentViewController
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^ __nullable)(void))completion
这个方法以前是presentModalViewController,字面意思就是推一个模态的ViewController。但是现在改成了presentViewController,具体原因不知道为什么。但是,从现象上看其实就是模态的。原因是通过presentViewController在“最上层”,举个例子就是,A1通过presentViewController,推了一个模态ViewController,A2。如果这个时候再让A1通过pushViewController推一个A3的话,你会看不到A3。原因是A3的view层级被A2的view遮挡了,也就是说A3在A2下面。
看看通过presentViewController后A2的层级结构:
发现A2的view实际上是被add到了window的UITrasitionView上,我猜测UITrasitionView的层级比UILayoutContainerView的层级要高(应该是肯定比UILayoutContainerView高),所以会出现上述情况。“人如其名”,presentViewController把viewController放在了最上面。
另外presentViewController默认支持一个从下到上出现的过场动画。
3.addChildViewController
[A1 addChildViewController:A2];
[A1.view addSubview:A2.view];
这种方式是直接将A2的view加到A1的view上