深入讲解iOS开发中的UIViewController

UIViewController顾名思义:视图控制器。应该在MVC设计模式中扮演控制层的角色。一些初学者在最开始的时候一直不理解为何有了UIView还要UIViewController做什么用,不都是向视图中增加view。在此我要声明一下
UIViewController和Uiview是两个不同的类UIViewController是视图控制器 而UIView是视图也就是说,UIViewController是控制UIView的。你也可以认为UIViewController就是一个相框,而UIView就是一个相片,相框可以随时随地的拿走这个相片而换另外一张相片,或者在这张相片上加一个新的相片。而相片却不能操纵相框的。 UIView工作在第一线,向用户展示表现的内容,并接受用户的交互。UIViewController相当于导演,按照计划编排属下的UIView以何种形式展现,其中包含一些花哨的技巧,如翻转、淡入淡出等。 UIVewController的另一个功能是处理用户交互操作,注意这里我说的是”处理”,当然UIViewController本身是不知道用户交互的,这就需要UIView将用户的交互操作(例如:touchesBegintouchesMoved)传递上来。一般常用的两种方法完成这种传递: 1、[self nextResponder] touchesBegin:touches… 2、使用Notification 不管以何种方式,如果UIViewController得到了用户的输入,那么它应该对UIView做些改变以响应用户的输入,这里要注意UIViewController应该只改变UIView的表现,而不应该处理其它事情,更多的操作通过Delegate来进行,关于Delegate的应用场合下次讲解消息的传递方式中一起阐述。请大家记住:UIView是一个视图,UIViewController是一个控制器,每一个viewController管理着一个view。
如果你开发的应用界面非常的简单,确实没有必要用控制器控制视图,但是对于视图中复杂的数据显示和数据处理,如果没有这个控制器,这样会使得代码的继承深度大大增加,不利于代码的阅读,首先看下官方API对UIViewController的解释:The UIViewController class provides the fundamental view-management model for iPhone applications(视图控制器为Iphone的应用程序提供了基础的视图管理模型) You use each instance of UIViewController to manage a view hierarchy(你可以使用视图控制器管理视图的继承)。从这里就可以看出,如果使用了视图控制器,你就可以方便的管理视图中的子视图,假如没有了这个控制器,可想而知每个视图岂不是都要用继承才能管理彼此的关系。
UIViewController的基础功能是管理界面中的view,但是一个复杂的应用程序肯定有好多的视图控制器,那么自然如果视图控制要有管理自己的功能就更加强大。先看API文档:View controllers rarely operate in isolation.If your application uses a navigation or tab bar controller,or if your application presents views modally,then it typically has several view controllers interacting with each other to implement those navigation features(视图控制器很少单独使用。假如你的应用程序要使用导航或者转换条控制器,或许是你的应用程序要呈现模态的视图,明显的这里有很多的视图控制器相互关联来实现导航的功能)。所以可以看出,UINavigationController和UITabBarController是用来控制视图控制器的使用的,同样他们的跟视图也是UIViewController,这里就说明了UIViewController是自己可以控制自己的。这也是为何我们使用UINavigationController的时候不允许在把一个NavigationController推入堆栈中,这样极容易形成自己队递归调用自己,造成堆栈溢出。以下是使用UIViewController应该注意的地方。
1.首先看loadView和viewDidLoad的区别,两者都是用来初始化试图控制器中的视图如何显示的。还是先看官方API解释:If you create your views manually, you must override this method and use it to create your views.If you use Interface Builder to create your views and initialize the view controller that is,you initialize the view using the initWithNibName:bundle: method,set the nibName and nibBundle properties directly, or create both your views and view controller in Interface Builder—then you must not override this method.(如果你手动创建一个视图控制器,你必须重载这个方法,去使用他创建你的视图。如果你使用Interface builder创建和初始化的视图控制器,你就不必重载此方法)。所以当你手动创建一个视图控制器的时候一定要注意重载loadView,否则你的视图将不回显示你增加的任何字视图。
2.viewDidUnLoad这个方法最容易误导人,先看API解释:Called when the controller's view is released from memory(当控制器的视图从内存中释放的时候被调用),个人觉得官方的解释对英语非母语的国家的人来说,很容易理解为视图控制器release的时候,调用此方法。但是如果实际调试以下,视图控制器释放的时候不会调用该方法。再进一步分析API文档:This method is called as a counterpart to the viewDidLoad method.
It is called during low memory conditions when the view controller needs to release its view
and any objects associated with that view to free up memory(这个方法是被调用相对于viewDidLoad方法的,在内存警告的情况下,当试图控制器需要释放它的视图和这个视图中相关联的任何对象来释放内存的时候,调用此方法)。这里还有一点要注意的时,当出现内存警告的时候,是调用正在显示的视图控制器的父视图控制器的viewdidUnload方法,而不是正在显示的视图控制器的viewDidUnload方法。因为如果调用了正在显示的视图控制器的viewDidUnload方法,那么用户正在看的界面就会消失,虽然释放了内存但是用户显然没法接受,自然要释放该视图下面看不到的视图控制器中的视图。被释放的视图,下次加载的时候再调用viewDidLoad的方法,所以ViewDidUnload的方法是和viewDidload方法相互对应的。

UIViewController生命周期
UIViewControl是IOS程序中的一个重要组成部分,扮演者一个大管家的身份,管理着程序中的众多视图,今天看看了官方文档并做了如下一些简单的记录:
 
何时加载view,加载的原则是什么,视图何时消失等问题,文档中讲的都很详细。
 
  Controller的view最好在需要显示时再去加载,并且在系统发出内存警告时释放比必要的view及相关的数据对象。
 
一、UIViewController的初始化
 
  初始化时会根据需要调用init,initWithCoder等相关函数,这个时候我们可以做一下简单的初始化操作,建立ViewController中需要使用的数据模型等,不建议在初始化阶段就直接创建view及其他与显示有关的对象(应该放到loadView的时候去创建,或者采用懒加载的方法创建)。
 
  我们都知道ViewController可以通过代码和xib两种方式创建,这两种方式的初始化流程也不尽相同。
 
  1)使用xib创建的VC
 
  xib其实最终是会把我们的设置保存成一个数据集,当需要初始化构建VC的时候,回去读取记录的数据集,然后帮我们动态的创建VC,因此可以想象它在初始化时会先去找看是否实现initWithCoder方法,如果该类实现了该方法,就直接调用initWithCoder方法创建对象,如果没有实现的话就调用init方法。调用完初始化方法以后紧接着会调用awakeFromNib方法,在这个方法里面我们可以做进一步的初始化操作。
 
  2)使用代码创建VC
 
  使用代码创建时,我们根据需要手动的创建VC中的数据,如果自己定制VC时,还需要在init中调用[super init]。
 
二、UIViewController中View的load和unload
 
  前面讲了不建议在VC初始化的时候就创建view及其他与显示相关的代码,官方文档建议将View的初始化操作放到loadView的时候再做,当VC接到内存告警时会调用didRecieveMemoryWarning这个时候我们就要做出响应,释放暂时不需要的对象。如果无视这个警告,系统内存不够用时会会继续发送,如果还得不到处理就会强制退出程序。下面看具体的loadView和unloadView时候都会做什么操作。
 
  1)Load周期

当需要显示或者访问view属性时,view没有创建的话,VC就会调用loadView方法,在这个时候会创建一个view并将其赋给VC.view属性。紧接着就会调用VC的viewDidLoad方法,这个时候VC.view保证是有值的,可以做进一步的初始化操作,例如添加一些subview。注意:定制VC时,如果覆盖loadView方法,不需要调用[super loadView]方法。
 
  2)Unload周期

当app收到内存警告的时候,会调用每一个VC的didRecieveMemoryWarning方法,我们需要做出响应,释放程序中暂时不需要的资源。通常都会重写该方法,重写时候需要调用super的该方法。如果检测到当前VC的view可以被安全释放的话,就会调用viewWillUnload方法,这个我们必须要重视,因为当VC的view消失时候它的subviews可能会被一起释放,我们需要根据具体情况做一些记录,以保证下次能够正确创建,同时不出现内存泄漏。调用viewWillUnload以后,会将VC.view属性设置成nil,然后在调用viewDidUnload方法,这个时候我们可以释放那些强引用的对象。