diff --git a/_posts/2012-05-16-custom-container-view-controller.md b/_posts/2012-05-16-custom-container-view-controller.md index 7e3862c..f877b83 100644 --- a/_posts/2012-05-16-custom-container-view-controller.md +++ b/_posts/2012-05-16-custom-container-view-controller.md @@ -8,19 +8,17 @@ tags: - UIViewController --- -> 苹果对UIViewController以及其使用有着非常详细的文档 [UIViewController Reference](http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIViewController_Class/Reference/Reference.html) , [ViewController Programming Guide](http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html)。 - ### 一.UIViewController 作为iOS开发, 经常会和UIViewController打交道,从类名便可知道UIViewController属于MVC模型中的C(Controller),说的更具体点它是一个视图控制器,管理着一个视图(view)。 -UIViewController的view是lazy loading的,当你访问其view属性的时候,它会从xib文件载入或者通过代码创建(覆盖loadView方法,自定义其view hierarchy),并返回view对象,如果要判断一个View Controller的view是否已经被加载需要通过其提供的isViewLoaded方法来判断。 +UIViewController的view是lazy loading的,当你访问其view属性的时候,view会从xib文件载入或者通过代码创建(覆盖loadView方法,自定义其view hierarchy),并返回,如果要判断一个View Controller的view是否已经被加载需要通过其提供的isViewLoaded方法来判断。 view加载后viewDidLoad会被调用,这里可以进行一些数据的请求或加载,用来更新你的界面。 当view将被加入view hierarchy中的时候viewWillAppear会被调用,view完成加入的时候viewDidAppear会被调用,同样当view将要从view hierarchy中移除的时候viewWillDisappear会被调用,完成移除的时候viewDidDisappear会被调用。 当内存紧张的时候,所有的UIViewController对象的didReceiveMemoryWarning会被调用,其默认实现是 如果当前viewController的view的superview是nil的话,则将view释放且viewDidUnload会被调用,viewDidUnload中你可以进行后继的内存清理工作(主要是界面元素的释放,当再次加载的时候需要重建)。 如果想要展示一个View Controller,一般有如下一种途径 -1. 设置成UIWindow的rootViewController(iOS 4.0之前UIWindow并没有rootViewController属性,只能通过addSubview的方式添加一个View Controller的view) +1. 设置成Window的rootViewController(iOS 4.0之前UIWindow并没有rootViewController属性,只能通过addSubview的方式添加一个View Controller的view) 2. 使用某个已经存在的Container来展示,比如使用UINavigationController来展示某个View Controller [navigationController pushViewController:vc animated:YES]; 3. 以模态界面的方式展现出来 presentModalViewController @@ -30,15 +28,16 @@ view加载后viewDidLoad会被调用,这里可以进行一些数据的请求 ### 二.Hierarchy -我们知道一个View可以将另一个View添加为子View(subview),构成一个View Hierarchy.当某一个View在keywindow(UIWindow继承于UIView)的View Hierarchy中时,是被“显示”的。每一个View Controller管理着的其实就是一个View Hierarchy.而View Controller本身可以有Child View Controller,所以也存在一个 View Controller Hierarchy的概念,当View Controller收到上层传来的事件(比如旋转,被显示)的时候,需要传递给它的Child View Controller. -一般情况下,我们需要保证View Hierarchy 和 View Controller Hierarchy保持一致,比如一个View Controller的view的superView是由其parent view controller管理着 +我们知道一个View可以将另一个View添加为子View(subview),构成一个View Hierarchy.当某一个View添加到window的View Hierarchy中时,将被“显示”。每一个View Controller管理着的其实就是一个View Hierarchy.而View Controller本身可以有Child View Controller,所以也存在一个 View Controller Hierarchy的概念,当View Controller收到上层传来的事件(比如旋转,被显示)的时候,需要传递给它的Child View Controller. +一般情况下,View Hierarchy 和 View Controller Hierarchy需要保持一致性,比如一个View Controller的view的superView是由其parent view controller管理着 +![Hierarchy](http://farm8.staticflickr.com/7105/7208538724_c77ed287c2_d.jpg) ### 三.Container 一个iOS的app很少只由一个ViewController组成,除非这个app极其简单。 当有多个View Controller的时候,我们就需要对这些View Controller进行管理。 -那些负责一个或者多个View Controller的展示并对其视图生命周期进行管理的对象,称之为容器,大部分容器本身也是一个View Controller,这样的容器可以称之为Container View Controller,有个别容器不是View Controller,比如UIPopoverController其继承于NSObject。 +那些负责一个或者多个View Controller的展示并对其视图生命周期进行管理的对象,称之为容器,大部分容器本身也是一个View Controller,这样的容器可以称之为Container View Controller,也有极少数容器不是View Controller,比如UIPopoverController,其继承于NSObject。 我们常用的容器有 UINavigationController,UITabbarController等,一般容器有一些共同的特征: @@ -47,9 +46,7 @@ view加载后viewDidLoad会被调用,这里可以进行一些数据的请求 3. 容器需要负责 Child View Controller的appearance callback的调用(viewWillAppear,viewDidAppear,viewWillDisaapper,viewDidDisappear),以及旋转事件的传递 4. 保证view hierarchy 和 view controller hierarchy 层级关系一致,通过parent view controller将child view controller和容器进行关联 -从上面可以看出来,实现一个Container View Controller并不是一个简单的事情,好在iPhone的界面大小有限,一般情况下一个View Controller的view都是充满界面或者系统自带容器的,我们无需自己创建额外的容器。 - -在iPhone上由于界面本身比较小,一般View Controller的view都是填充满的,所以系统自带的容器就够用了。但是在iPad中情况就不同了。 +从上面可以看出来,实现一个Container View Controller并不是一个简单的事情,好在iPhone的界面大小有限,一般情况下一个View Controller的view都是充满界面或者系统自带容器的,我们无需自己创建额外的容器,但是在iPad中情况就不同了。 @@ -80,7 +77,7 @@ iOS 5中otherViewController是可以立刻收到viewWillAppear和viewDidAppear 当我们需要在iOS 4上实现自定义容器,或者有时候我们不想让viewWillAppear这类方法被自动调用,而是想自己来控制,这个时候我们就得需要手动来调用这些方法,而不是由框架去自动调用。 iOS 5中可以很方便的禁用掉自动调用的特性,覆盖automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers返回NO -但是单单覆盖这个方法在iOS5下还是有问题的, +但是单单覆盖这个方法在iOS5下还是有问题的,当执行下面的语句的时候 {% highlight objc %} [viewController.view addSubview:otherViewController.view] @@ -94,7 +91,7 @@ otherViewController还是是可以立刻收到viewWillAppear和viewDidAppear的 {% endhighlight %} -实现兼容iOS 4和iOS 5的容器还是有不少问题和注意点的 +总的来说实现兼容iOS 4和iOS 5的容器有不少问题和注意点的 1. view加入view层级前后分别调用viewWillAppear和viewDidAppear;容器的viewWillAppear,viewDidAppear,viewWillDisappear,viewDidDisappear中需要对当前显示的Child View Controller调用相同的方法 2. 容器的shouldAutorotateToInterfaceOrientation中需要检测每一个Child View Controller的shouldAutorotateToInterfaceOrientation如果一个不支持,则看做不支持 @@ -102,3 +99,8 @@ otherViewController还是是可以立刻收到viewWillAppear和viewDidAppear的 4. 由于UIViewController的parentViewController属性为只读,且iOS4中没有提供容器支持的接口(iOS 5中容器支持的接口会间接的维护这个属性),所以为了使得childViewController和容器得以关联,我们可以顶一个View Controller的基类,添加一个比如叫做superController的属性用来指定对应的parentViewController 5. 由于UIViewController的interfaceOrientation为只读属性,且iOS5中没有提供容器接口,所以UIViewController的这个interfaceOrientation变的不可性,为了取得当前UIViewController的orientation我们可以用UIWindow下的rootViewController的interfaceOrientation的值 6. 容器的viewDidUnload方法中需要对view未释放的childViewController的view进行释放,且调用其viewDidUnload方法 + + + + +> 苹果对UIViewController以及其使用有着非常详细的文档 [UIViewController Reference](http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIViewController_Class/Reference/Reference.html) , [ViewController Programming Guide](http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html)。