IOS应用编程是基于事件驱动的编程。也就是说,应用的流程由事件来决定:事件包括系统事件和用户操作。界面上用户执行的操作会触发事件。这些事件导致应用的逻辑被执行,数据被操作。应用对用户动作的响应反映在界面上。因为是用户——不是开发者——控制了应用的某些特定代码片断被执行,因此,你一定要确定一个用户可以执行哪些操作,这些操作被执行后又会发生什么响应。
在视图控制器中,你定义了大量的事件处理逻辑。控制器通过响应用户的动作和填充视图的内容来支撑视图。控制器像是一个管道,通过它,视图和数据模型之间可以发生交互。通过应用的控制器,通知视图数据模型发生改变了,控制器把用户发起的改变(例如在text field中键入文本)告知给模型对象。不论是响应了用户的动作还是定义了导航,控制器都实现了应用的行为。
视图控制器
在你构建完一个基本的视图层次结构后,你的下一步操作是控制可以元素,响应用户输入。在IOS应用中,在子视图的层次结构中,使用视图控制器(UIViewController)管理视图。
视图控制器不是视图层次结构的组成部分,它也不是界面上的元素。相反,它在层次结构中管理着视图对象,它为视图提供行为。在storyboard中建立的每个内容视图层次结构都需要相应的视图控制器,这是为了管理界面元素和执行用于响应用户交互的任务。这通常也就意味着为每一个内容视图层次结构写一个自定义的UIViewController的子类。如果应用有多个内容视图,为每个内容视图都应该使用不同的自定义的控制器。
视图控制器扮演着多种角色。它协调应用的数据模型和显示数据的视图之间的信息交互,它管理内容视图的生命周期,它处理当设备旋转时屏幕方向的改变。虽然它有这么多角色,但是它最主要的角色或许就是响应用户的输入。
你应该使用视图控制器来实现不同内容之间的过渡。因为IOS应用用于显示内容的空间是有限的,因此,视图控制器提供了删除无用的视图、添加有用视图的功能。
为了定义应用中的交互,你应该使视图控制器文件和storyboard中的视图有联系。通过使用action和outlet,你就可以建立storyboard和源代码文件的联系。
Action
action是被链接到应用中发生事件上的代码片断。如果事件发生,那么这些代码片断就被执行。从操作数据到更新用户界面,你可以定义action来完成任何事情。为了响应用户或系统的事件,你定义action来驱动应用的流动。
通过创建和实现返回类型为IBAction、参数类型为id的方法,来定义action。
-
- (IBAction)restoreDefaults:(id)sender;
sender参数指向的就是被触发动作的响应者。IBAction返回类型是一个特殊的关键字。它有点类似于void关键字,但是它代表的意思是该方法是你在Interface Builder中可以从storyboard连接的action(这就是为什么该关键字以IB开头)。如果你想了解更多关于把一个IBAction类型的action链接到storyboard中的某个元素上的知识,请参见 Tutorial: Storyboards章节。
Outlet
outlet提供了从源文件中引用界面对象(添加到storyboard中的对象)的方法。创建outlet的方法是:按住Control键,从storyboard中把某个对象拖动到某个视图控制器文件中。这样的操作就会在视图控制器文件中为这个对象创建一个属性,在运行时,你可以通过该属性来获取和操作该对象。例如,在前面的教程中,你已经为text field创建了一个outlet,这样,你就可以在代码中获取它里面的内容了。
IBOutlet关键字用于定义outlet属性。
-
@property (weak, nonatomic) IBOutlet UITextField *textField;
IBOutlet关键字告诉Xcode:已经把该属性连接到Interface Builder中了。如果你想了解如何在storyboard和源码文件之间建立outlet连接的知识,请参见 Tutorial: Storyboards章节。
Control
control(控件)就是用户界面对象,例如button,slider,switch等,在应用中,用户操作control(控件)来与内容交互、提供输入、导航等,还能使用它们执行自己定义的其它操作。control(控件)可以让你的代码接收来自于用户界面的消息。
当用户与control进行交互时,control(控件)事件就被创建了。control(控件)事件是各种用户可以控制的物理手势,例如手指从一个控件上抬起,手指从控件外面滑动到控件上,在text field中按下等。
control(控件)事件的一般分类有三种:
触摸并拖动事件:当用户使用触摸或拖动的方式与控件交互时发生该类事件。例如,当用户刚把手指放在按钮上时,Touch Down Inside事件被触发。如果用户手指从按钮上拖动到按钮外,那么drag事件被触发。当用户从按钮上抬起手指并且手指仍然在按钮边缘的范围之内时,Touch Up Inside事件被触发。如果用户在抬起手指之前,把手指拖动到按钮范围之外,那么就有效的阻止了Touch事件的发生,取而代之的是,Touch Up Outside事件被触发。
编辑事件:当用户在text field里进行编辑时发生。
值改变事件:当用户操作control(控件),使其发生一系列不同值的时候发生。
在定义交互时,了解应用中每个控件与之相关联的动作,在界面上确保用户能明白control(控件)的意图。
导航控制器
如果应用有多个内容视图层次结构,那么,你需要能在它们之间进行转换。对于这种情况来说,你需要使用一种特别的视图控制器:navigation controller(UINavigationController)。通过一系列的视图控制器,navigation controller管理着向后和向前的转换,例如,在IOS邮件应用中,用户可以通过导航进入邮件账户,收件箱,个人邮件页面等。
由特别的navigation controller所管理的视图控制器的设置被称为它的导航栈。导航栈是自定义视图控制器对象的后进先出的集合。首先被加入栈中的元素成为根视图控制器,是永远不会从导航栈中弹出的。
尽管导航控制器的主要工作是管理内容视图控制器的显示,但是,它也有自己的自定义视图。明确地说,它提供了一个导航栏——在屏幕的基部,可以提供导航层次结构中用户当前所处的位置——导航栏包含了一个返回按钮和其它可以自定义的按钮。每个被添加到导航栈中的视图控制器都代表着导航栏。你要负责配置导航栏。
一般来说,你不需要做任何工具,就可以从导航栈中弹出视图控制器,由导航控制器提供的返回按钮会为你处理这件事情的。但是,你必须手动把视图控制器压入栈中,你可以使用storyboard来完成这件事情。
使用storyboard定义导航
到目前为止,你已经学习了如何在应用中使用storyboard创建单个屏幕的内容。现在,你将学习如何在应用中使用storyboard定义多个屏幕之间的流程。
在一开始的教程中,所使用的storyboard只有一个场景。在大多数应用里,一个storyboard是由一系列有序的场景所组成,每个场景都代表着一个视图控制器和视图层次结构。场景由segue连接,segue代表着两个视图控制器之间的过渡:一个是源,一个是目的地。
在storyboard中,你可以创建这么几种类型的segue:
show:show类型的segue会把一个新的内容压到当前视图控制器的栈顶。内容出现的位置依赖于场景中视图控制器的布局。
show detail:show detail类型的segue,要么把一个新的内容压到当前视图控制器的栈顶,要么会替换当前显示的内容,具体采用哪种方式,依赖于场景中视图控制器的布局。
present modally:模态的segue是在一个视图控制器中模态地弹出另外一个视图控制器,一般需要用户在返回到应用的主流程之前,在弹出的模态视图控制器中执行某个操作。模态控制器不会被添加到导航栈中,相反,它一般被认为是当前视图控制器的孩子。当前的视图控制器负责它所创建和展现的模态控制器的消失。
popover presentation:presented的视图控制器是一个弹出窗口,被锚到一个已经存在的视图上。
custom:可以通过实现UIStoryboardSegue的子类来定义自定义的过渡。
Unwind:unwind segue向后移动一个或多个segue,可以让用户返回到视图控制器已经存在的某个实例。你可以使用unwind segue来实现反转导航。
场景除了使用segue来连接,场景还可以使用relationship连接。例如,在两个导航控制器之间有一个relationship和它们的根视图控制器。在这种情况下,relationship代表着由导航控制器包含的根视图控制器。
到现在为止,你已经学习了在storyboard中操作视图和视图控制器的基础知识。下节教程是时候把你学到的知识融入到ToDoList应用中了。