iPhone编程中心采用两种重要的范例:面向对象编程和模型—视图—控制器(MVC)设计模式。iPhone SDK在设计时考虑了在开发人员构建的程序中支持这些概念。为此,它引入了委托(控制器)、数据源方法(模型)和定制的视图类(视图)。下面简要介绍本书所使用的一些重要的iPhone/Cocoa Touch设计术语。
1.9.1 面向对象编程
Objective-C在很大程度上基于Smalltalk,后者是历史上最为重要的一种面向对象的语言。面向对象编程使用封装和继承的概念来构建可重用的类,这些类使用已经发布的外部接口和私有的内部实现。应用程序将通过一些能够像乐高玩具一样整合在一起的具体类来实现,这些类通过类声明明确彼此之间的关系。
伪多重继承(通过调用转发和协议)提供了Objective-C面向对象编程方法中的一个重要特性。iPhone类可以从多个父类继承行为和数据类型。以UITextView类为例,它既是文本,也是视图。与其他视图类似,它可以出现在屏幕上。它有边界以及指定的不透明度。同时,它还继承了一些特定于文本的行为。你可以很容易地修改其显示字体、颜色或文本大小。Objective-C和Cocoa Touch将这些行为结合在一个易于使用的类中。
1.9.2 模型—视图—控制器
MVC将屏幕对象的外观和行为分开。屏幕上的按钮(视图)没有内在含义。它只是用户可以按下的按钮。此视图的控制器充当媒介。它将用户交互(如按钮单击)与应用程序中的目标方法(即模型)连接在一起。应用程序提供和保存有意义的数据,并通过生成某种有用的结果来响应按钮单击等交互。
各MVC元素彼此独立运作。举例来说,可以将单击按钮换成拨动开关,而无需修改模型或控制器。程序会继续像原来一样运行,但GUI现在会拥有不同的外观。或者可以保持界面不变,在模型中修改触发应用程序按钮时的响应方式。通过分开这些元素,可以构建可维护、可独立更新的程序组件。
iPhone上的MVC范例分为以下类别。
·模型——模型方法通过数据源和数据含义之类的协议提供数据,需实现由控制器触发的回调方法。
·视图——视图组件由UIView类的子类提供,并由与其相关的UIViewController类辅助(这样说可能有些不妥)。
·控制器——控制器行为通过3种关键技术实现:委托、目标操作和通知。
这3种元素是MVC编程范例的主要部分。让我们详细了解一下iPhone MVC设计模式的这些元素。以下小节将介绍各元素及其支持类。
1. 视图类
iPhone在构建视图时基于两个重要的类:UIView和UIViewController。这两个类和它们的子类负责定义和放置所有屏幕元素。
视图在屏幕上绘制事物时,UIView代表最抽象的视图类。几乎所有用户界面类都继承自UIView及其父类UIResponder。视图提供组成应用程序的所有可视元素。重要的UIView类包括UITextViews、UIImageViews和UIAlertViews等。UIWindow类(一种UIView)提供一个到应用程序的视口,并提供了显示的基本框架。
由于其屏幕特性,所有视图都建立了某种类型的框架。这是一个屏幕上的矩形框,它定义了各视图所占的空间。该矩形框根据视图的原点和宽度而建立。
视图为分层结构,由子视图树组成。要显示某个视图,可以将它设置为主窗口的内容视图,或者将它添加到另一个视图中,方法是使用addSubview方法为父视图分配一个子视图。可以将视图看做是向屏幕添加的几层透明薄膜,每个视图都有各自的绘图。最后添加的视图就是当前看到的视图。较早添加的视图可能被其上的视图遮住。
严格来说,UIViewController类并不是MVC概念中的控制器,这与它的名称不符。它们更多情况下是充当视图处理器和模型,而不是控制器。也许有人不同意这一点,苹果公司的术语并非总是与计算机课程所教授的MVC范例相一致。
视图控制器可以简化开发人员的工作。它们负责根据用户手持iPhone的方式来旋转屏幕显示。在使用导航栏或工具栏时,它们将重新调整视图的大小以使其适合边界。它们处理所有界面事务,并将直接管理交互元素所涉及的复杂性隐藏在底层。开发人员在设计和构建iPhone应用程序时不必再使用UIViewController或其子类,但为什么还要使用?因为该类提供了极大的便利性,编写应用程序时不使用它是得不偿失的。
除了基控制器的方向和视图重新调整大小的支持之外,UINavigationController和UITabBar- Controller这两个特殊的控制器可以神奇地处理视图切换。导航控制器支持向下扩展视图,在各视图间平滑地切换显示。导航控制器会记住视图显示的顺序,并提供完整的“返回”按钮痕迹导航,因此不必额外编程就可返回之前的视图。
选项卡视图控制器允许使用选项卡式的显示方式,可方便地在视图控制器实例之间来回切换。因此,如果应用程序有10大项目列表、游戏窗口和帮助表,可以添加一个含有3个按钮的选项卡栏,用于在这些视图之间迅速切换,而不需要任何额外编程。
无论是通过实现一个LoadView方法,还是使用.xib文件中已构建的接口并调用viewDidLoad,每个UIViewController子类都实现了自己的用于加载视图的方法。正是该方法对控制器的主视图进行布局。它还可能创建触发器、回调和委托,如果之前没有在Interface Builder中创建它们的话。
因此,单就这方面而言,UIViewController算不上一个控制器,它在界面外观和交互解释方式之间提供这些链接。并且,由于你几乎总是要向UIViewController本身发送回调,因此除了主要充当创建的和要显示的视图的控制器之外,它通常还充当应用程序的模型。它并不是特别符合MVC概念,但非常方便并且易于实现。
2. 控制器
苹果公司在设计滑块和表之类的交互式元素时,他们不知道用户会如何使用这些元素。经过精心设计,类具有通用性。对于MVC来说,并没有与行选择或按钮单击相关的编程含义。这需要开发人员提供模型来添加含义。iPhone为预构建的Cocoa Touch类提供了一些与自定义类交流的方式。下面介绍最重要的3种方式:委托、目标操作和通知。
3. 委托
许多UIKit类都使用委托交出响应用户交互的责任。在设置某个对象的委托时,便是让对象将任何交互消息传递出去,让该委托负责处理这些事务。
UITableViews就是一个很好的例子。当用户单击某个表行时,UITableView没有响应该单击操作的内置方式。这个类是通用的,没有与单击相关联的语义。但是,它会请示委托(通常是一个视图控制器类或主应用程序委托)并通过一个委托方法传递选择更改。这样,你就可以将表类首次实现的时间与给单击添加含义的时间完全分离开。委托使得类可以在没有这些含义的情况下创建类,同时确保特定于应用程序的处理器可以在稍后添加。
UITableView委托方法tableView: didSelectRowAtIndexPath:就是一个典型的例子。模型将控制此方法,并实现它对行更改的响应方式。可以显示一个菜单或导航到一个子视图,或靠近当前选择放置一个选中标记。响应完全依赖于实现委托选择更改方法的方式。
要设置某个对象的委托,可以指定它的委托属性(首要事项),或者使用setDelegate:方法的一些变体。这可以指示应用程序将交互回调重定向到委托。通过在类声明中添加它所实现的委托协议说明,可以让Xcode知道对象实现了委托调用。该说明位于类继承右侧的尖括号中。代码清单1-1显示了一种UIViewController,它实现了UITableView视图的委托方法。因此,MergedTableController类负责实现所有需要的表委托方法。
Xcode的文档详尽地列出了所有标准委托方法,包括必需的和可选的。打开Help(帮助)→Documentation(文档)(Command-Option-Shift-?),搜索委托名称,如UITableViewController Delegate。该文档提供了委托方法可以或必须实现的实例方法的一个列表。
委托并不仅限于苹果公司提供的类。可以方便地在类中添加自己的协议声明,并使用它们定义回调词汇。代码清单1-1创建了FTPHostDelegate协议,该协议声明了ftpHost实例变量。在使用时,对象必须实现协议中声明的所有3个(必需的)方法。协议是Objective-C编程中一个令人兴奋的强大部分,通过它可以创建保证能支持主类所需的所有功能的客户端类。
说明 如果应用程序是围绕中心表视图构建的,可以使用UITableViewController实例简化表的创建和使用。
代码清单1-1 在类定义中定义和添加委托协议声明