present/push的恩怨情仇
push/pop
简介
pushViewController 导航控制器入栈的方式切换页面
popViewController
导航控制器出栈的方式返回上一页面
VC栈存储
container view controller
container view controller 指的是VC的容器类,通过container view controller,我们可以很方便的管理子VC,实现VC之间的跳转等,iOS中container view controller包括 UINavigationController, UISplitViewController, 以及 UIPageViewController.
push/pop是将旧视图存储在了VC栈中,因此我们可以这样操作:
假如
从A—(push)—>B—(push)—>C—(push)—>D—(popToRootViewController)—>A
如果在D视图进行操作:
NSLog(@"%@",self.navigationController.viewControllers);
则会打印:
2019-09-28 19:42:50.576198+0800 1111[995:32530] (
"<AViewController: 0x7fdc41d00480>",
"<BViewController: 0x7fdc3ec0a010>",
"<CViewController: 0x7fdc3ef1b1e0>",
"<DViewController: 0x7fdc3ef1b530>"
)
这就是push的VC栈的内容。
因此,我们可以进行这样的pop跳转:
[self.navigationController popToViewController:self.navigationController.viewControllers[0] animated:YES];
这是因为我们可以看到,viewControllers
是NSArray
类型的,所以可以通过下标跳转到指定界面。
优势
VC栈存储的优势在于:
-
可以直接跳转到根视图:
- 通过
popToRootViewController
方法,把栈清空,直接回到根视图。
- 通过
-
可以跳转到指定界面:
- 通过
popToViewController:
方法 和NSArray
类型的viewControllers
,可以跳转到指定的视图。
- 通过
dealloc
那么,在我们通过popToRootViewController
方法回到根视图的时候,A视图后面的B、C、D视图会怎样呢?
答案是:按数组顺序依次销毁。
可以通过在B、C、D视图添加:
- (void)dealloc {
NSLog(@"当前视图名称 dealloc");
}
可以发现,最后会这样打印:
2019-09-28 20:00:39.291619+0800 1111[1108:40814] AViewController viewWillAppear
2019-09-28 20:00:39.296359+0800 1111[1108:40814] BViewController dealloc
2019-09-28 20:00:39.296798+0800 1111[1108:40814] CViewController dealloc
2019-09-28 20:00:39.802419+0800 1111[1108:40814] DViewController dealloc
会先出现A视图,然后按数组顺序依次dealloc。
也就是说,它是按栈存储的,但是并不符合后进先出的原理。(???)
可能是把栈里的视图先取出,放到里另一个栈sNew里,当top指的是根视图时,先把根视图显示,再把栈sNew里的视图依次移除
navigationController
讨论push/pop
,就不得不讨论navigationController
。
无navigationController的界面push
当我们从一个有navigationController
的A界面用present
跳转到B界面后,B界面将没有navigationController
,若还在B界面用push
方法,即如下:
CViewController *cViewController = [[CViewController alloc]init];
NSLog(@"跳转到C界面");
[self.navigationController pushViewController:cViewController animated:YES];
则界面不会跳转,会一直停留在B界面&#