你使用类UIViewController 的自定义子类来呈现你的应用程序的内容。大多数自定义的视图控制器都是内容视图控制器,也就是说,它们拥有自己的视图而且负责管理这些视图的数据。相比之下,容器视图控制器不拥有它的全部视图,它的一些视图被其它的视图控制器管理。定义内容和容器视图控制器的大多数步骤都是相同的,在接下来的内容里会对此做一些讨论。
对于内容视图控制器,最常见的父类是如下这些:
-当你的容器视图控制器的主要视图是一个table的时候,应该明确使用UITableViewController。
-当你的容器视图控制器的主要视图是一个collection 视图的时候,应该明确使用UICollectionViewController。
-对于其它的视图控制器,使用UIViewController。
对于容器视图控制器,使用什么父类取决于你是打算修改一个已存在的容器类还是创建你自己的容器类。对于已经存在的容器,选择你想要修改的那个容器类。对于新的内容视图控制器,你通常可以子类化UIViewController。更多关于创建容器视图控制器的额外信息,see Implementing a Container View Controller
定义你的UI
在Xcode中,为你的视图控制器定义可视化的UI,通常是使用storyboard 文件。尽管你也可以用编码的方式来创建你的UI,但是storyboards是一个极好的方式,用来为不同的设备环境可视化你视图控制器的内容和按需定制你的视图层次结构。可视化的构建你的UI程序,可以让你很快的改变UI界面,并且不用构建和运行你的app就可以看到你在UI上做出的改变。
图4-1展示了一个storyboard的例子,每个矩形区域代表一个视图控制器和与该视图控制器相关联的视图。视图控制器之间的箭头符号代表视图控制器之间的relationships和segues。Relationships 是一个容器视图控制器和它的子视图控制器之间的连接关系。在你的界面中,Segues 可以让你在视图控制器之间navigate。
图4-1 一个storyboard留有一组视图控制器和视图
每个新建的工程都有一个main storyboard,典型地,它已经包含了一个活着多个视图控制器。你可以添加新的视图控制器到你的storyboard,在library 中通过拖动的方式把视图拖到画布中。新的视图控制器在最开始的时候没有与它相关联的类,所以你必须在Identity inspector面板中给它指派一个。
使用storyboard editor 可以做如下这些事:
-添加,组织和配置视图控制器中的视图。
-连接outlets和actions;see Handling User Interactions.
-在你的视图控制器中创建relationships 和 segues ;see Using Segues.
-为不同的size classes 定制布局和视图;see Building an Adaptive Interface.
-添加手势识别来在视图上处理用户交互; see Event Handling Guide for iOS.
如果在使用storyboards来创建你的界面方面你是一个新手,你可以在 Start Developing iOS APPs Today 中按照说明一步一步的来创建你的storyboard-based 界面。
处理用户交互
一个app的responder objects 处理传入进来的事件并且采取相应的actions来处理。尽管视图控制器是responder objects,但是它们很少直接处理touch事件,Instead,视图控制器处理事件的典型方法如下:
- 视图控制器定义了action methods 来处理higher-level 事件。Action methods 响应:
--特定的动作。控制装置和一些视图调用一个action 方法来通知特定的交互。
--手势识别。手势识别调用一个action 方法来通知当前的手势状态。使用你的视图控制器来处理状态的改变或者响应完整的手势。
- 视图控制器observe 被系统或者是其它对象传送过来的notifications。Notifications 通知改变,而且是视图控制器更新状态的一种方法。
- 视图控制器作为其它对象的一个data source 或者 delegate。视图控制器经常被用来管理table和collection视图的数据。你也可以使用视图控制器作为一个对象的delegate,例如一个CLLocationManager 对象,发送位置更新信息给它的delegate。
响应事件经常涉及到更新视图的内容,响应事件需要拥有指向所更新的视图的引用。视图控制器是为视图定义你稍后需要修改的插座变量的好地方。用下面Listing4-1中展示的语法来声明你的插座变量属性,在下面列表中的自定义类定义了两个插座变量(被IBOutlet 关键字指定)和一个单一的动作方法(被指定为IBAction返回类型)。在storyboard中,插座变量存储指向一个button和一个text field 的引用,同时action方法响应button按钮中的taps。
Listing4-1 在视图控制器类中定义outlets和actions
OBJECTIVE-C @interfaceMyViewController : UIViewController @property(weak,nonatomic)IBOutlet UIButton *myButton; @property(weak,nonatomic)IBOutlet UITextField *myTextField; -(IBAction)myButtonAction:(id)sender; @end
SWIFT classMyViewController: UIViewController { @IBOutletweak var myButton : UIButton! @IBOutletweak var myTextField : UITextField! @IBActionfunc myButtonAction(sender:id) }
在运行时展示你的视图
Storyboards loading 和 displaying 你的视图控制器的视图的过程时非常简单的。当需要的时候,UIKit 自动的从你的storyboard 文件中加载。作为加载过程的一部分,UIKit 执行下面一系列的任务:
1.用你的storyboard 文件中的信息实例化视图。
2.连接所有的outlets 和 actions。
3.为视图控制器的view属性指派根视图。
4.调用视图控制器的awakeFromNib 方法。 当这个方法被调用时,视图控制器的trait collection 是空的,而且视图可能不是在它们最终的位置。
5. 调用视图控制器的viewDidLoad 方法。 使用这个方法为你的视图添加或者移除视图,修改布局约束,加载数据。
在视图控制器的视图显示到屏幕上之前和之后,UIKit 提供给你一些额外的机会来准备这些视图。Specifically,UIKIt之行下面一些列任务:
1.调用视图控制器的viewWillAppear:方法,让它知道它的视图将被显示到屏幕上。
2.更新视图的布局。
3.显示视图到屏幕上。
4.当视图在屏幕上时调用viewDidAppear:方法。
当你添加,移除或者修改视图的大小或者位置时,记得添加或者移除引用到这些视图上的布局约束,否则你视图层次结构的约束关系改变时,将造成UIKit 标记到脏的布局。在下一个更新循环期间,布局引起使用当前的布局约束来计算视图的大小和位置,并将这些改变应用到视图层次结构。
更多关于怎样不使用storyboards创建视图的信息,看视图管理信息,in UIViewController Class Reference.
视图布局管理
当你的视图的大小和位置改变时,UIKit 为你的视图层次结构更新布局信息。为了让视图配置使用自动布局,UIKit采用自动布局引擎来根据当前的约束来更新布局。UIKit 也让其它感兴趣的对象知道与它们相邻接的布局的改变,好让它们能够做出响应的应答,比如被激活的presentation controller。
在布局处理期间,UIKit 通知你数个点,让你可以执行额外的layout-related 任务。使用这些通知来修改你的布局约束或者是在布局约束被应用之前做出最后的微调。在布局处理期间,UIKit 为布局影响的视图控制器做下面这些事:
1.根据需要更新视图控制器的trait collection 和它的视图;see When Do Trait and Size Changes Happen?
2.调用视图控制器的方法 viewWillLayoutSubviews。
3.调用当前UIPresentationController 对象的containerViewWillLayoutSubviews 方法。
4.调用这个视图控制器根视图的layoutSubviews 方法。 这个方法的默认实现事使用有效的约束来计算新的布局信息。然后这个方法穿过视图层次调用每个子视图的layoutSubviews 方法。
5.应用计算的布局信息到视图上。
6.调用视图控制器的viewDidLayoutSubviews 方法。
7.调用当前UIPresentationController 对象的containerViewDidLayoutSubviews 方法。
视图控制器可以使用viewWillLayoutSubview 和 viewDidLayoutSubviews 方法来执行额外的更新,这样可能会对布局过程造成影响。在布局之前,你可以添加或者移除视图,更新视图的大小和位置,更新约束,活着更新其它view-related 属性。在布局之后,你可以重新加载table 数据,更新其它的视图内容,或者是对视图的大小和位置做出最后的调整。
下面是一些有效管理你的视图布局的技巧:
- 使用自动布局。使用自动布局创建的约束是一种灵活和容易的方式,用来在不同尺寸的屏幕上放置你的内容。
- 充分利用顶部和底部布局向导。在这些向导上放置内容可以确保你的内容总是可见的。The top layout guide 的位置把status bar和navigation bar的高度也纳入了考虑因素。同样地,The bottom layout guide也把tab bar 或者toolbar 纳入了考虑因素。
- 当你添加或者移除视图时记得更新约束。如果你动态地添加或者移除视图,记得更新响应的视图约束。
- 当animating 你的视图控制的视图的时候,临时移除布局约束。当你使用UIKit Core Animation animating 视图的时候,为animations的持续时间内移除你的约束,当animations结束的时候添加它们到后台。如果在animation 期间你的视图的大小和位置发生了改变,记得更新约束。
更多关于presentation controllers 和它们在视图控制器架构中所扮演的角色的信息,see The Presentation and Transition Process
有效地管理内存
尽管分配内存的大多数方面是由你决定的,表4-1列出了类UIViewController 中最可能分配和释放内存的方法。大多数的释放都涉及到移除对象的强引用,为了移除对象的强引用,设置属性和变量所指向的对象为nil。
Table 4-1 Places to allocate and deallocate memory