iOS的SDK中提供不少原生ViewController,大大提升了咱们的开发效率,下面是个人一些经验。编程
1、结构xcode
按结构能够对iOS的全部ViewController分红两类:app
一、主要用于展现内容的ViewController,这种ViewController主要用于为用户展现内容,并与用户交互,如UITableViewController,UIViewController。函数
二、用于控制和显示其余ViewController的ViewController。这种ViewController通常都是一个ViewController的容器。如UINavigationController,UITabbarController。它们都有一个属性:viewControllers。其中UINavigationController表示一种Stack式结构,push一个ViewController或pop一次,所以后一个ViewController会依赖前一个ViewController。而UITabbarController表示一个Array结构,各个ViewController是并列的。性能
第一种ViewController会常常被继承,用来显示不一样的数据给用户。而第二种不多被继承,除非你真的须要自定义它。学习
注:细心的同窗应该能发现,在xcode中新建一个ViewController时,只能够继承自UIViewController和UITableViewController,而它们都是第一种。动画
图1ui
2、Controller和View的生命周期atom
这里指的View是指Controller的View。它做为Controller的属性,生命周期在Controller的生命周期内。就是说你的Controller不能在view释放前就释放了。spa
图2 ViewController生命周期
当你alloc并init了一个ViewController时,这个ViewController应该是尚未建立view的。ViewController的view是使用lazyInit方式建立,就是说你调用的view属性的getter:[self view]。在getter里会先判断view是否建立,若是没有建立,那么会调用loadView来建立view。loadView完成时会继续调用viewDidLoad。loadView和viewDidLoad的一个区别就是:loadView时尚未view。而viewDidLoad时view以及建立好了。
当view被添加其余view中以前时,会调用viewWillAppear,而以后会调用viewDidAppear。
当view从其余view中移出以前时,会调用viewWillDisAppear,而以后会调用viewDidDisappear。
当view不在使用,并且时disappeared,受到内存警告时,那么viewController会将view释放并其指为nil。
3、代码组织(如何设计良好的viewController)
ViewController生命周期中有那么多函数,一个重要问题就是什么代码该写在什么地方。
一、init里不要出现建立view的代码。良好的设计,在init里应该只有相关数据的初始化,并且这些数据都是比较关键的数据。init里不要掉self.view,不然会致使viewcontroller建立view。(由于view是lazyinit的)。
二、loadView中只初始化view,通常用于建立比较关键的view如tableViewController的tabView,UINavigationController的navgationBar,不可调用view的getter(在调super loadView前),最好也不要重载这个方法。
三、viewDidLoad 这时候view已经有了,最适合建立一些附加的view和控件了。有一点须要注意的是,viewDidLoad会调用屡次(viewcontroller可能屡次载入view,参见图2)。
四、viewWillAppear 这个通常在view被添加到superview以前,切换动画以前调用。在这里能够进行一些显示前的处理。好比键盘弹出,一些特殊的过程动画(好比状态条和navigationbar颜色)。
五、viewDidAppear 通常用于显示后,在切换动画后,若是有须要的操做,能够在这里加入相关代码。
六、viewDidUnload 这时候viewController的view已是nil了。因为这通常发生在内存警告时,因此在这里你应该将那些不在显示的view释放了。好比你在viewcontroller的view上加了一个label,并且这个label是viewcontroller的属性,那么你要把这个属性设置成nil,以避免占用没必要要的内存,而这个label在viewDidLoad时会从新建立。
在我以前的学习笔记中讨论过ViewController,过了这么久,对它也有了新的认识和体会,ViewController是咱们在开发过程当中碰到最多的朋友,今天就来好好认识一下它。ViewController是iOS开发中MVC模式中的C,ViewController是view的controller,ViewController的职责主要包括管理内部各个view的加载显示和卸载,同时负责与其余ViewController的通讯和协调。在iOS中,有两类ViewController,一类是显示内容的,好比UIViewController、UITableViewController等,同时还能够自定义继承自UIViewController的ViewController;另外一类ViewController容器,UINavigationViewController和UITabBarController等,UINavigationController是以Stack的形式来存储和管理ViewController,UITabBarController是以Array的形式来管理ViewController。和Android中Activity同样,iOS开发中,ViewController也有本身的生命周期(Lifecycle)。
首先来看看View的加载过程,以下图:
从图中能够看到,在view加载过程当中首先会调用loadView方法,在这个方法中主要完成一些view的初始化工做,好比UINavigationViewController和UITabBarController等容器类的ViewController;接下来就是加载view,加载成功后,会接着调用viewDidLoad方法,这里要记住的一点是,在loadview以前,是没有view的,也就是说,在这以前,view尚未被初始化。完成viewDidLoad方法后,ViewController里面就成功的加载view了,如上图右下角所示。
在Controller中建立view有两种方式,一种是经过代码建立、一种是经过Storyboard或Interface Builder来建立,后者能够比较直观的配置view的外观和属性,Storyboard配合iOS6后推出的AutoLayout,应该是Apple以后主推的一种UI定制的解决方案,后期我会专门介绍一篇使用AutoLayout进行UI制做的文章。言归正传,经过IB或Storyboard建立view,在Controller中建立view后,会在Controller中对view进行一些操做,会出现以下代码:
这里用IBOutlet标记了一个UIButton和一个UITextField,用IBAction来标记UIButton的响应事件,IBOutlet和IBAction都是一个整形常量,用来标记控件,经过一张图能比较清晰的看清他们之间的关系:
上图中,MyViewController是继承自UIViewController的一个自定义ViewController,它包含两个view,一个是UIButton,一个是UITextField,从箭头的指向性上就能够较好的理解IBOutlet和IBAction了。IBOutlet是告诉Interface Builder,此实例变量被链接到nib文件中的view对象,IBOutlet自己不作任何操做,只是一个标记做用。IBAction一样是个标记关键字,它只能标记方法,它IB用IBAction标记的方法能够被某个控件触发。
经过编程的方式建立view,以下代码:
上述代码首先获得屏幕的frame,而后根据frame生成了一个contentView,并指定当前ViewController的root view为contentView,而后生成了一个LevelView的自定义View并将它经过addSubview:方法添加到当前ViewController当中,完成view的初始化加载。
关于loadView方法的重写,官方文档中有一个明显的注释,原文以下:
Note: When overriding the loadView
method to create your views programmatically, you should not call super
. Doing so initiates the default view-loading behavior and usually just wastes CPU cycles. Your own implementation of the loadView
method should do all the work that is needed to create a root view and subviews for your view controller.
意思是当经过代码方式去建立你本身的view时,在loadView方法中不该该调用super,若是调用[super loadView]会影响CPU性能。
接下来咱们看看ViewController中的view是如何被卸载的:
从图中能够看到,当系统发出内存警告时,会调用didReceiveMemoeryWarning方法,若是当前有能释放的view,系统会调用viewWillUnload方法来释放view,完成后调用viewDidUnload方法,至此,view就被卸载了。此时原来指向view的变量要被置为nil,具体操做是在viewDidUnload方法中调用self.myButton = nil;
小结一下:
loadView和viewDidLoad的区别就是,loadView时view尚未生成,viewDidLoad时,view已经生成了,loadView只会被调用一次,而viewDidLoad可能会被调用屡次(view可能会被屡次加载),当view被添加到其余view中以前,会调用viewWillAppear,以后会调用viewDidAppear。当view从其余view中移除以前,调用viewWillDisAppear,移除以后会调用viewDidDisappear。当view再也不使用时,受到内存警告时,ViewController会将view释放并将其指向为nil。
ViewController的生命周期中各方法执行流程以下:
init—>loadView—>viewDidLoad—>viewWillApper—>viewDidApper—>viewWillDisapper—>viewDidDisapper—>viewWillUnload->viewDidUnload—>dealloc