苹果原来的开发文档已更新,此翻译已过时。。。
来源自苹果开发文档ViewController Programming Guide for iOS
View Controller Basics
运行在基于iOS设备的应用程序只有有限的屏幕空间来显示内容,因此他们如何给用户呈现信息必须有创造性。那些有很多信息需要显示的应用程序在开始时因此只能显示一部分,然后当用户跟应用程序交互时显示和隐藏额外的内容。视图控制器对象为管理内容和协调内容的显示和隐藏提供了基础设置。通过拥有不同的视图控制器类控制用户界面的单独部分,你把用户界面的实现分成几个更小更容易管理的单元。
在你能在应用程序中使用视图控制器之前,你徐啊要对爱iOS应用程序中用来显示内容的主要类有一个基本的理解,包括窗口和视图。任何视图控制器实现的关键部分是管理显示内容的视图。但是,管理视图不是视图控制器执行的唯一工作。当过渡发生时,大多是视图控制器还跟其他视图控制器交流和协调。因为视图控制器管理着很多链接,包括内部的视图和相关对象的链接以及外部的其它控制器之间的链接,理解对象之间的各种链接有时候很困难。作为替代,使用界面生成器来创建故事板。故事板让应用程序中的关系的可视化更简单并大大简化初始化对象在运行时所需的努力
一、屏幕,窗口和视图创建可视化界面
图1-1显示了一个简单的界面。左侧,你可以看见组成该界面的各种对象并理解它们是如何互相连接的。
图1-1
这里有三个主要对象在工作:
- 一个UIScreen对象表示连接到设备的一个物理屏幕。
- 一个UIWindow对象为屏幕提供绘图支持
- 一组UIView对象来执行绘图。这些对象被连接到窗口,当窗口要求它们回执内容时绘制。
图1-2显示了这些类(以及相关重要类)在UIKit中如何被定义。
图1-2
尽管你不需要理解关于视图的所有知识,进而理解视图控制器,但是它在考虑视图的最显著功能上很有帮助:
- 一个视图表示一个用户界面元素。每个视图覆盖了一个特定的区域。在那个区域中,它显示内容或响应用户事件。
- 在一个视图层次机构里可以被嵌套。子视图相对于它们的子视图定位和绘制。因此,当父视图发生移动,其子视图也跟着移动。该层次结构通过把它们放在一个通用父类中让集合一组相关视图变得容易。
- 视图可以动画它们的属性值。当一个属性值的改变发生动画时,该属性值在定义的时间区内逐渐改变直到它达到目标新值。交叉在多个视图的多个属性的改变可以在一个动画里协调动画。
- 动画对于iOS应用程序开发是至关重要的。因为大多数应用程序在一个时间只显示内容的一部分,动画允许用户看到一个过渡何时发生以及新内容从哪来。一个瞬间过渡可能让用户困惑。
- 视图很少理解它们在应用程序中扮演的角色。比如,图1-1显示了一个按钮(标题hello),它是视图的一种特殊形式,被称为控件。控件知道如何响应用户在该区域的交互,但是它们不知道它们该控制什么。相反,当用户控件发生交互时,它给应用程序中的其它对象发送消息。该灵活性允许一个单类(UIButton)提供多个按钮的实现,每个都能出发一个不同的操作。
一个复杂的应用程序需要很多视图,这些视图都被组合进视图层次结构里。它需要动画这些视图的子集到屏幕或使其离开屏幕来提供一个更大界面的错觉。最后,保持视图类可重用,视图类需要对它们在应用程序中执行的特殊角色一无所知。所以应用程序逻辑(大脑)还需要被放在其他地方。视图控制器就是把应用程序的视图联系到一起的大脑。
二、视图控制器管理视图
每个视图控制器都组织管理一个视图;该视图常常是一个视图层次结构中的根视图。视图控制器就是MVC模式里的控制器对象,但是视图控制器还有特殊任务iOS期望它去执行。这些任务由UIViewController类定义,所有视图控制器都从它这继承。所有视图控制器执行视图和资源管理任务;其他职责取决于如何使用视图控制器。
图1-3显示了从图1-1延伸而来的界面,但是这里添加了一个视图控制器。你绝不是直接把视图分派到窗口上。你应该给窗口分派一个视图控制器,然后视图控制器自动添加其视图给窗口。
图1-3 一个附加到窗口的视图控制器自动添加其视图到窗口,使它们成为窗口的子视图。
图1-3
视图控制器只在视图被需要时才小心的加载该视图。他还能在特定条件下释放该视图。因为这些原因,视图控制器在管理应用程序中的资源方面起着关键作用。
视图控制器是协调其所有被管理视图的行为的原始地方。比如,当一个按钮被按下,它给视图控制器发送了一个消息。尽管视图本身可能不知道它执行的任务,但是视图控制器应该知道按钮下意味着什么,以及它该如何响应。控制器可能更新数据对象,动画或改变存储在其视图中的属性值,或甚至把另一个视图控制器的内容显示到屏幕上。
通常应用程序实例化的每个视图控制器只显示应用程序数据的一个子集。它知道如何显示那个特殊的数据集,而不需要了解其它类型的数据。因此,一个应用程序数据模型,用户接口设计,以及你创建的视图控制器都互相影响。
图1-4显示了一个管理食谱的应用程序。该应用程序显示了三个相关到时独立的视图。第一个视图列出了应用程序管理的食谱。点击一个食谱显示第二个视图,它描述了选中的视图。点击详细视图中的食谱图片,打开第三个视图,一张放大的图片。每个视图都有一个独立的视图控制器对象管理--呈现适当的视图,用数据填充子视图,以及在视图层次结构里响应用户交互。
图1-4
该例子说明了视图控制器的一些常见要素:
- 每个视图都只被一个视图控制器管理。当一个视图被分配给视图控制器的view属性,视图控制器就拥有了该视图。如果视图是一个子视图,它可能被同一个或不同的视图控制器。当你学习容器视图控制器(container view controllers)时,你将学习到更多关于如何使用多个视图控制器来组织一个单一的视图层次结构。
- 每个视图控制器跟应用程序数据的一个子集发生交互。比如,Photo Controller 只需要知道要显示的照片。
- 因为每个视图控制器只提供用户体验的一个子集,视图控制器必须相互交流来让该体验完美衔接。它们还可能跟其他控制器相交流,比如数据控制器或文档对象。
三、视图控制器的分类
图1-5显示了UIKit框架中可用的视图控制器类,以及其它对视图控制器很重要的类。比如,UITabBarController对象管理一个UITabBar对象,UITabBar对象实际上显示了跟标签界面相关的标签。其它框架定义的额外的视图控制器类没有显示在该图中。
图1-5 UIKit中的视图控制器类
视图控制器,不管是那些由iOS提供的还是你自己定义的视图控制器,都可以被分为两个基本类别(内容视图控制器和容器视图控制器),它们反应了视图控制器在应用程序中扮演的角色。
1.内容视图控制器显示内容
内容视图控制器使用一个视图或一个由一组视图组成的视图层次结构在屏幕上呈现内容。之前描述的控制器已经有内容视图控制器。一个内容视图控制器通常知道应用程序数据的子集,该数据跟控制器在应用程序中所扮演的角色有关。
以下列出了应用程序使用内容视图控制器的常用地方:
- 给用户显示数据
- 从用户那收集数据
- 执行一个指定任务
- 在一组可行命令或选项之间导航,比如一个游戏的启动屏幕
内容视图控制器是应用程序的主要协调对象,因为它们知道数据和应用程序提供给用户的任务的具体详情。
你创建的每个内容视图控制器对象负责管理一个但已是图层次结构中的所有视图。一个视图控制器和其视图层次结构中所有视图之间的一对一对应关系是主要的设计考虑。你不应该使用多个内容视图控制器来管理同一个视图层次。同样的,你也不应该使用一个单一内容视图控制器对象来管理多个屏幕上的内容价值。
关于定义你的内容视图控制器以及实现所需的行为的信息,请看Creating Custom Content View Controllers
1)关于表格视图控制器
很多应用程序显示表格数据。因此,iOS提供了一个专门用来管理表格数据的内建的UIViewController的子类。UITableViewController管理一个表哥视图并支持很多标准表格相关的行为,比如选择(selection)管理,行编辑,以及表格配置。这些额外的支持减少了你创建和初始化一个基于表格界面必须编写的代码总量。你还可以子类化UITableViewController来添加其它自定义行为。
图1-6显示了一个使用表格视图控制器的例子。因为它是UIViewController的一个子类,表格视图控制器仍然有一个指向接口根视图的指针(通过其view属性)
图1-6
更多关于表视图的信息,请查看Table View Programming Guide for iOS
2.容器视图控制器安排其它视图控制器的内容
容器视图控制器包含了其他视图控制器拥有的内容。这些其它视图控制器都明确地被作为其子视图控制器分配给容器视图控制器。一个容器视图控制器可以是其它控制器的父控制器也可以是另一个控制器的子控制器。最终,这些控制器的组合建立一个视图层次结构。
每种类型的容器视图控制器建立了一个让其子控制器能在里面操作的用户界面。该用户界面的视觉呈现,以及它施加给自控制器的设计可以在不同类型的容器之间广阔地变化。比如,以下有一些方法让不同的容器视图控制器可以区分它们自己:
- 一个容器提供它自己的API来管理其子控制器。
- 一个容器决定子控制器之间是否有关系,以及什么关系。
- 一个容器跟其它视图控制器一样一个视图层次。一个容器还可以添加子控制器的任何视图到它的层次。容器决定何时添加这样的一个视图,以及它应该如何被调整尺寸以适应容器的视图层次结构,但是除此之外子视图控制器保留了对视图和其子视图的职责。
- 一个容器可能施加特定设计构思到其子控制器。比如,一个容器可能一些特定的视图控制器类限制其子控制器,或它可能期望那些控制器来提供额外起的内容来配置容器的视图。
每个内建的容器类都围绕着一个重要的用户界面原则来组织。你可以使用这些容器管理的用户界面来组织复杂的应用程序。
1)关于导航控制器
导航控制器呈现按层次组织的数据,它是UINavigationController类的一个实例。该类的方法对管理一个基于栈的内容视图控制器集合提供支持。该栈表示用户通过层次数据获取的路径,栈的末端反应起始点,栈的顶端反应洪湖在数据中的当前位置。
图1-7显示了通讯录应用程序的屏幕,它使用一个导航控制器来呈现联络信息给用户。每个页面顶部的导航栏是导航控制器所有。每个屏幕显示给用户的其余部分是由一个内容视图控制器管理,内容视图控制器显示数据层次中特定层的信息。当用户在界面中跟控件发生交互,那些控件告诉导航控制器显示序列中的下一个视图控制器或丢弃当前的视图控制器。
图1-7
尽管一个导航控制器的主要任务是管理它的子视图控制器,但是它还管理一些视图。特别是,它管理一个导航栏(显示用户在数据层次中的当前位置信息),一个按钮(导航到前一个屏幕),以及当前视图控制器需要的任何自定义控件。你不能直接修改视图控制器拥有的视图。作为替代,你配置控件,这些控件由导航控制器显示,它们通过设置在每个子视图控制器上的属性来显示。
关于如何配置和使用导航控件对象的信息,请看Navigation Controllers。
2)关于标签栏控制器
标签栏控制器是一个容器视图控制器,你可以用它来把应用程序分成两个或更多不同的操作模式。标签栏控制器是UITabBarController类的一个实例。标签栏有多个标签,每个表示一个子视图控制器。选择一个标签导致标签栏控制器在屏幕上显示相关视图控制器的视图。
图1-8 显示了Clock应用程序的集中模式,以及相关视图控制器之间的关系。每个模式都有一个内容视图控制器来管理主要内容区域。在Clock应用程序中,Clock和Alarm视图控制器都显示一个导航风格的界面来沿着屏幕的顶部容纳一些额外的控件。其它模式使用内容视图控制器来呈现一个单一屏幕。
图1-8
当你的应用程序呈现不同种类数据或者以不同方式呈现相同数据的时候,你可以使用标签栏控制器。
关于如何卑职和使用一个标签栏,请看Tab Bar Controllers
3)关于拆分视图控制器
拆分视图控制器是把屏幕分成多个部分,每个部分都可以被单独更新。一个拆分视图控制器的外形可能很大程度上依赖于它的方向。拆分视图控制器是UISplitViewController类的一个实例。一个拆分视图界面的内容来源于两个子视图控制器。
图1-9显示了MultipleDetailViews例子应用程序中的一个拆分视图界面。在竖直模式,只有详细视图被显示。列表视图用一个弹出菜单(popover)打开。然而,当屏幕处于水平模式时,拆分视图控制器一边一个显示两个子视图控制器的内容。
图1-9
拆分视图控制器仅在iPad上支持,旨在帮助您利用该设备的打屏幕。它们是iPad应用程序中实现主-细节界面的首选方法。
关于如何配置和使用一个拆分视图控制器的信息,请看Popovers
4)关于弹出视图控制器
再次看图1-9,当拆分视图控制器以竖直模式显示时,主视图在一个特殊的控件中显示,被成为popover。在一个iPad应用程序中,你可以使用popover控制器(UIPopoverController)来实现弹出控件。
弹出控制器实际上不是一个容器,它不继承自UIViewController。但,实践中,弹出视图控制器跟容器很相似,所以你在使用它们时可以应用相同的编程原则。
关于更多如何设置和使用弹出控制器的信息,请查看Popovers
5)关于页面视图控制器
页面视图控制器是一个容器视图控制器,它用来实现一个页面布局。那个布局允许用户翻转内容的不同页面,就好像翻书一样。页面视图控制器是UIPageViewController类的一个实例。每个内容页由一个内容视图控制器提供。页面视图控制器管理页面之间的过渡。当需要新页面时,页面上视图控制器调用一个相关的数据源来为下一个页面取回一个视图控制器。
关于如何配置和使用一个页面视图控制器的信息,请看Page View Controllers
四、一个视图控制器的内容可以以不同的方式显示
要想把一个视图控制器的内容显示给用户,它必须关联一个窗口。你可以在应用程序中使用以下方法来实现:
- 把视图控制器作为窗口的根视图控制器
- 把视图控制器作为一个容器的子控制器
- 在一个弹出控件中显示视图控制器
- 从另一个视图控制器中呈现它
图1-10显示了联系人应用程序的一个例子。当用户点击加号来添加一个新联系方式时,联系人视图控制器呈现添加联系人视图控制器。添加联系人屏幕保持可见知道用户取消操作或为联系方式提供了足够的信息让其保存到联系人数据库中。在那时信息被发送给联系人视图控制器,然后丢弃呈现的控制器。
图1-10
被呈现的视图控制器没有指定类型---可以是内容视图控制器也可以是带有一个内容视图控制器的容器视图控制器。实践中,内容视图控制器是专门设计为能让另一个控制器呈现,因此把它想象成一个内容视图控制器的变量会很有帮助。尽管容器视图控制器定义了被管理控制器之间的特定关系,但是使用presentation允许你定义被呈现的视图控制器和呈现它的视图控制器之间的关系。
大多数时间,你被呈现视图控制器来收集用户或为一些特定目的捕捉用户的注意力。一旦那个目的完成,被呈现的视图控制器和呈现它的视图控制器之间的关系。
一个被呈现的视图控制器本身还可以呈现另一个视图控制器,这点值得注意。当你需要线性的执行多个模型动作时,这个把视图控制器链接到一起的功能会很有用。比如,如果用户点击图1-10中的New Contact屏幕上的添加照片按钮,想要选择一张已经存在的图片,New Contact视图控制器呈现一个图片选择器界面。用户必须丢弃图片选择器屏幕,然后单独地丢弃New Contact屏幕返回到联系人列表。
当呈现一个视图控制器时,一个视图控制器决定花费多少屏幕来呈现视图控制器。屏幕部分默认被称为呈现上下文,呈现上下文被定义用来覆盖窗口。
关于如何在应用程序中呈现视图控制器的更多信息,请看Presenting View Controllers from Other View Controllers
五、视图控制器一起工作创建一个应用程序的界面
视图控制器管理它们的视图以及其它相关对象,但是它们还是跟其它视图控制器一起提供一个无缝的用户界面。您的应用程序的视图控制器之间的工作和交流的分配是与它们一起工作的一个重要组成部分。因为这些关系对于建立复杂应用程序是如此重要,下一节回顾已经讨论过的关系,并介绍了它们更多细节。
1.父子关系表示包含
一个视图控制器层次结构以一个单一父控制器开始,即窗口的根视图控制器。如果那个视图控制器是一个容器,它可能有提供内容的子控制器。那些子控制器相应地也可能是它们自己的子控制器的容器。图1-11显示了一个视图控制器层次结构。根视图控制器是一个带有4个标签的标签视图控制器。第一个标签使用一个带有自己的子控制器的导航控制器,其它三个标签由内容视图控制器管理,它们没有子控制器。
图1-11
每个视图控制器填充的区域由其父控制器决定。跟视图控制器的区域是由窗口决定的。在图1-11中,标签视图控制器从窗口获取它的尺寸。它给标签栏留出空间,并把剩余空间给子视图。如果导航控制器是刚刚显示的控件,它给导航栏留出控件,并把剩余空间留给内容控制器。在每个步骤,子视图控制器的视图由父视图重新调整尺寸并放入父视图的视图层次结构中。
该视图和视图控制器的组合还为应用程序处理事件建立了响应链。
2.同胞关系代表一个容器内的同级
容器的类型定义了其子视图控制器共享的关系(如果存在)。比如,比较标签视图控制器和导航控制器。
- 在一个标签视图控制器中,标签标示内容的独立屏幕;标签栏控制器没有给它的子视图控制器定义一个关系,尽管你的应用程序可以这么做。
- 在一个导航栏控制器中,显示同胞的相关视图被安排在一个栈中。同胞常常跟相连的同胞共享一个连接。
旅途1-12显示了跟导航控制器有关的一个通用视图控制器配置。第一个子控制器Master显示了不显示所有的细节可用的内容。当一个数据被选择时,它推送一个新的同胞到导航控制器,这样用户就能看到额外的细节。想似的,如果油壶需要查看更多细节,该同胞可以推送另一个视图控制器来显示可用的最详细内容。当同胞们有像该例子中的一个良好定义,它们常常直接或通过容器控制器互相协作。参考图1-15
图1-12
3.呈现表示另一个界面的瞬时显示
当一个视图控制器想要另一个视图控制器执行一个任务时,它呈现另一个视图控制器。呈现它的视图控制器管理该行为。它配置被呈现的视图控制器,从它那接收信息,并最终丢弃它。然而,当它被呈现时,被呈现的视图控制器的视图暂时被添加到窗口的视图层次结构中。
图1-13,一个连接到标签视图的内容视图呈现了一个视图控制器来执行一个任务。Content是呈现视图控制器,Modal视图控制器是被呈现的视图控制器。
图1-13
当一个视图控制器被呈现时,它覆盖的一部分屏幕由另一个视图控制器提供的呈现上下文定义。提供呈现上下文的视图控制器不需要跟呈现它的视图控制器是同一个。图1-14显示了跟图1-13同样的视图控制器层次。你可以看到内容视图呈现了视图控制器,但是它不提供呈现上下文。相反,视图控制器由标签控制器所呈现。因此,即使呈现的视图控制器只覆盖了标签视图控制器提供给它的部分屏幕,但是被呈现的视图控制器仍然使用了标签视图控制器所拥有的整个区域。
图1-14
4.控制流表示内容控制器之间的整个协作
拥有多个视图控制器的应用程序,视图控制器的创建和销毁通常贯穿于应用程序的整个生命周期。在生命周期中,视图控制器互相交流以呈现一个无缝的用户体验。这些关系代表应用程序的控制流。
这样的控制流最常见的发生时间是当一个新的视图控制器被实例化时。通常,一个视图控制器被实例化是因为另一个视图控制器中的动作。第一个视图控制器,被成为源视图控制器引出第二个视图控制器,即目标视图控制器。如果目标视图控制器需要给用户呈现数据,源视图控制器常常提供那些数据。相似地,如果源视图控制器需要从目标视图控制器获取信息,它负责建立两个视图控制器之间的连接。
图1-15显示了这些关系的最通用例子
图中:
- 一个导航控制器的一个子控制器推送另一个子控制器到导航栈。
- 一个视图控制器呈现另一个视图控制器。
- 一个视图控制器在一个弹出菜单里显示另一个视图控制器。
每个控制器都有前一个控制器所配置。当多个控制器一起工作,它们建立一个贯穿整个应用程序的交流链。
链中每个连接的控制流都由目标视图控制器定义。源视图控制器使用目标视图控制器提供的各种约定。
- 目标视图控制器提供用来配置其数据和呈现的各种属性。
- 如果目标视图控制器需要跟链中前一个视图控制器交流,它使用委托。当源视图控制器配置目标视图控制器的其他属性,它还应该提供一个实现委托协议的对象。
使用该控制流约定的好处是它让每对源和目标视图控制器之间有一个清楚的责任分工。当源视图控制器要求目标视图控制器执行一个任务时,数据沿着路径往下流动;源视图控制器驱动该进程。比如,它可能提供目标控制器应该显示的特定数据。在一个方向,当一个视图控制器需要把交流信息传回催生它的源控制器时,数据沿着路径向上流动。比如它可能在任务完成时发生交流。
此外,通过持续实现这种控制流模型,你还可以确保目标视图控制器绝不会知道关于源视图控制器的太多配置信息。即使它确实了解关于链中的前一个视图控制器。它也只知道实现委托协议的类,而不是类中的类。为了防止视图控制器之间了解太多,让控制器们独立变得更加重要。对于阅读你的代码的其他人,一个持续实现的控制流模型让它能很容易就看到任何一对控制器之间的交流路径
六、故事板帮助你设计用户界面
当你用故事板实现你的应用程序时,你可以使用界面生成器来组织你的应用程序视图控制器以及任何相关视图。图1-16显示了界面生成器上的一个界面。Interface Builder中的可视化布局一目了然,让您可以了解您的应用程序中的流。你可以看到哪些视图控制器是由应用程序实例化的,以及它们被实例化的顺序。更重要的是,你可以配置视图的复杂集合以及故事板中的其它对象。由次产生的故事板作为一个文件被存储在项目中。当你建立项目时,项目中的故事板被处理并拷贝到应用程序束(bundle)中,在那里它们在运行时有应用程序加载。
图1-16
通常,iOS能根据需要在故事板中自动实例化视图控制器。相似的,跟每个控制器相关的视图层次在它需要被显示时自动被加载。视图控制器和视图都以界面生成器中的相同配置被实例化。因为大多数该行为都是自动化为你完成的,所以它极大地简化了在应用程序中使用视图控制器的所需的工作。
关于创建故事板的完整细节在Xcode User Guide中有描述。目前,你需要知道一些在应用程序中实现故事板所需的必要术语。
一个场景表示一个屏幕上的内容区域,它由一个视图控制器管理。你可以把场景想象成一个视图控制器以及其相关的视图层次结构。
你在同一个故事板中创建场景之间的关系。关系在一个故事板中用从一个场景到另一个场景的一个连接箭头可视化表达。当你在两个对象之间做一个连接时,界面生成器通常自动推断一个新关系的细节。存在两种重要类型的关系:
-
包含表示两个场景之间的一个父子关系。当父控制器被实例化时,包含在其它视图控制器里的视图控制器也被实例化。比如,从一个导航控制器到另一个场景的第一个链接定义了把第一个视图控制器推送到导航栈。该控制器在导航控制器被实例化时自动被实例化。
在一个故事板转哦给你使用包含关系的一个好处是Interface Builder可以调整子视图控制器的外形来反映其祖先的存在。当内容视图控制器出现在你的最终应用程序中时,这样做允许Interface Builder显示内容视图控制器。
-
Segue表示从一个场景到另一个场景的一个可视化过渡。在运动时,segues可以由不同的动作触发。当一个segue被触发时,它导致一个新视图控制器被实例化并过渡到屏幕上。
尽管一个segue 总是从一个视图控制器到另一个,有时该过程中可以涉及第三个对象。该对象实际触发segue。比如,如果你做一个连接从一个按钮(该按钮在源视图控制器的视图层次结构中)到目标视图控制器,当用户点击该按钮,segue被触发。当直接从源视图控制器到目标视图控制器做一个segue,它通常表示你打算通过程序触发一个segue。
不同类型的segues 提供了两个不同视图控制器之间所需的常用的过渡:- Push segue 把目标视图控制器推送到一个导航控制器栈中。
- Modal segue 表示目标视图控制器。
- Popover segue 在一个popover里显示目标视图控制器。
- Custom segue 允许你设计自己的过渡来显示目标视图控制器。
Segues共享一个通用编程模型。在该模型中,目标控制器由iOS自动实例化,然后调用源视图控制器来配置它。该行为符合控制流模型,该模型在Control Flow Represents Overall Coordination Between Content Controllers.中描述。
你还可以在一个视图控制器和存醋在同一个场景中的对象之间创建链接。这些Outlets和Actions让你能仔细的定义视图控制器和其相关对象之间的关系。关系本身在故事板中不是默认可见的,但是它们能在Interface Builder中的Connections Inspector中查看。