viewcontroller在app的硬软件资源管理中占据着重要的作用,它的设计哲学在于将app切分成多个部分,只实例化现时需要的那部分,而viewcontroller自身也不停地操纵着它所管理的资源。比如viewcontroller的view树只有在view被访问到的时候才会实例化,严格来说只有在view显示在屏幕上的时候才会被使用到。当多个viewcontroller同时被push到navigation stack中的时候,只有最顶部的viewcontroller内容可见,即只有其view被使用到。同样地,如果一个viewcontroller当前并不是被navigation controller所呈现,则不必实例化navigation item。通过这种延迟加载资源的方式,view controller得以在最小的资源负担运行。
viewcontroller管理UI
view被使用到的时候,如果其当前并不在内存中,则viewcontroller会将view加载进内存并将其赋值给其view属性,过程如下:
1 viewcontroller调用load view方法,在loadView默认实现中,若其与storyboard关联,则从storyboard中加载view,否则创建空的view,然后将赋值view属性
2 调用viewdidload方法以进行额外的工作
注:其实可以试试viewcontroller在关联了storyboard的情况下,再重载loadView会发生什么情况,虽然只有在手动创建View的时候才会调用用户自己重载过的loadView,否则会直接从Storyboard 中加载view
如果通过完全通过编程方式来创建View,则需要注意的是由于viewcontroller的view会由于各种原因被resize,所以在loadview的过程中即使将创建的root view frame设置为window的frame值,最终呈现效果可能会根据场景的不同而不同,详见附注1
viewcontroller管理内存
需要进行内存分配及释放的地方有如下场景:init场景,loadView, viewDidload, didReceiveMemoryWarning, dealloc,当然还有在任意场景 创建及析构自定义对象的自由。
需要注意的是,在didReceiveMemoryWarning可以 释放对view的引用(听起来好可怕),代码示例如下
以及,dealloc需要做真正需要在最后一刻释放及清理的操作,同时实例变量太属性不需要显式释放,因为它们会自动被释放
附注1 view controller的view resize
view controller可以管理自己的view,但大多数情况下view的frame是由view controller被呈现的方式所决定的。比如状态栏存在时,view的frame会被改变。
--- window设置rootviewcontroller的view的frame, 其设置的frame的实际值受如下因素影响:
1 window的frame本身的大小
2 状态栏是否可见
3 状态栏是否在呈现临时的额外信息(比如来电信息)
4 UI的orientation
5 rootviewcontroller的wantsFullScreenLayout属性
若要显示状态栏,view会缩小以不被状态栏覆盖,因为如果状态栏是不透明的话,用户是无法与被其覆盖的内容交互的。若状态栏是透明的,可以设置viewcontroller的wantsFullScreenLayout属性为YES以允许view全屏显示。此时状态栏是在view的上面显示的。
由于用户无法与透明状态栏(或者透明导航条和工具条)下面的内容交互,所以在view全屏时将内容置于scrollview之中是很有必要的。导航条会自动添加一个scroll content inset到你的scroll view(假设这是viewcontroller的根view)以考虑到导航条的高度,否则必须手动设置scroll view的contentinset。
--- 容器设置子view的frame
viewcontroller为其他容器viewcontroller的孩子的时候,子viewcontroller的view会被当做子view添加进view树中,并得到相应的frame: 比如tab view controller在底部维护tab bar,剩余的空间作为子View的frame,navigation view controller会在屏幕顶部保留一个导航条的位置,剩余位置使用当前可见子view controller的View填充
--- 被呈现的viewcontroller会受限于呈现viewcontroller的frame
--- view controller在view layout中的发生作用的步骤如下:1 view controller的view resize到新size 2 若未使用Autolayout,views们会根据autoresizing mask进行Resize 3 view controller的 viewwilllayoutsubviews方法被调用 4 view的layoutsubviews方法被调用,如果使用auto layout,则通过如下步骤更新layout限制:a 调用view controller的updateviewconstraints方法 b viewcontroller的updateviewconstraits方法调用view的updateConstraints方法 c layout constraints更新之后,会计算新的layout并重置各view的位置 5 view controller的viewdidlayoutsubviews方法调用
想知道,不使用autolayout的时候,会不会有viewwilllayout方法被调用?