前言
看这篇博客之前,先安利一片文章《View Debugging in Xcode 6》,英文能力有限也没关系,译文:《详解Xcode 6的视图调试》。
一句代码引起了我的注意
今天在看到别人的代码的时候,发现了下面这样一句代码:
1 | [[UIApplication sharedApplication].delegate.window addSubview:self.shareView]; |
在 UIWindow 上面去添加视图(self.shareView)。
自己写代码的习惯是会写成下面这种形式:
1 | [[UIApplication sharedApplication].delegate.window.rootViewController.view addSubview:self.shareView]; |
添加到根控制器(rootViewController)的视图也是可以显示,和上面的代码有一样的效果,那他们究竟有什么样的区别呢?
视图层级
添加到window与添加到rootViewController.view的区别
我们将两个相同的 UIImageView 添加到 window 和 rootViewController.view(rootViewController为UINavigationController),push 一个新的 UIViewController 后,在 viewDidLoad
方法下运行:
1 | UIWindow *window = [UIApplication sharedApplication].delegate.window; |
会有如下的效果:
乍一看没有什么区别?如果没有区别,我写这博客干嘛呢,是吧?哈哈哈~
通过Xcode来观察他们的视图层级结构
xcode 工作区点击以下这两步:
可以看到如下的视图层级图:
左侧栏可以看出其层级结构:
添加到 rootViewController.view 的 UIImageView 被添加到 UILayoutContainerView 底下。
添加到 UIWindow 的 UIImageView 被添加到 UIWindow 底下。
表象上看,两个 UIImageView 都是显示在视图的顶端,但是实际上层级结构不一样。
各个视图层级的作用
UINavigationController 为 rootViewController
我们看下面的这张图是:
UILayoutContainerView:最底层包含所有视图的容器。
UINavigationTransitionView:导航控制器在这里发生转场行为的容器视图。
UIViewControllerWrapperView: 包含 viewController 的 view属性的封装视图。
UIView: viewController 的最上层视图 (与viewController的view 属性一致)
要记得,当我们通过 [UIApplication sharedApplication].delegate.window.rootViewController.view 去获取一个 View,即使 UINavigationController 没有push任何视图,你拿到还是最底层的 UILayoutContainerView。而不是 顶层的 UIView。
UITabBarController 为 rootViewController
UIViewController 为 rootViewController
回到最初的起点
我们回到刚刚上面的两句代码,其实这两句代码都是有点小“问题”的:
问题1
1 | [[UIApplication sharedApplication].delegate.window addSubview:self.shareView]; |
不能使用于 rootViewController 的 viewDidLoad 方法中。会出现以下这种情况:
在 rootViewController 还没有加载完毕时,已经将视图添加到 UIWindow 中了,后面会因为 rootViewController 的加载而挡住原来的视图。
问题2
1 | [[UIApplication sharedApplication].delegate.window.rootViewController.view addSubview:self.shareView]; |
在模态视图下不可使用,模态视图的出现会,销毁之前的我们 rootViewController.view,导致我们只能看到一闪而过的效果,view 不能长久的停留在屏幕上。
问题3
在 stackoverflow,当别人提起 UILayoutContainerView 时,很多的建议都是不要在上面做操作,因为他并非官方开放给开发者使用的接口。
所以我们还是避免使用:
1 | [[UIApplication sharedApplication].delegate.window.rootViewController.view addSubview:self.shareView]; |
自己要改掉该习惯。
最后的话
关于 iOS 的视图层级,如果要更深入的去研究的话,还是推荐去官方文档翻一翻,可能显示的开发会跟这一块打交道的机会不是很多,但是要真正深入的去了解iOS的视图机制,还是属于要跨过去的坎。