Documentation Archive Developer
Search

了解您的应用程序的核心对象

UIKit 框架为所有应用程序提供基础结构,但仍然需要您自定对象来赋予应用程序的具体行为。您的应用程序,由一些特定的 UIKit 对象组成,这些 UIKit 对象管理事件循环以及与 iOS 的主要交互。通过组合运用子类化、委托和其他技巧,您可以修改 UIKit 所定义的默认行为,来实现您的应用程序。

除了自定 UIKit 对象以外,您还需要负责提供或定义其他多组关键的对象。最大的一组对象,是应用程序的数据对象,它们的定义,完全由您负责。您还必须提供一套用户界面对象。幸运的是,UIKit 提供了许多类,让您轻松地定义界面。除编程以外,您还必须提供资源和数据文件,这些文件是交付可发行应用程序所需要的。

iOS App Programming Guide》(iOS 应用程序编程指南)详细描述了此文章中提及的许多主题。

应用程序的核心对象

从用户启动您的应用程序直到退出,UIKit 框架管理着应用程序的许多核心行为。应用程序的心脏,是 UIApplication 对象,它从系统接收事件,然后将事件分派到您的自定代码进行处理。其他 UIKit 类也参与应用程序行为的部分管理,所有这些类都使用相似的方式,调用您的自定代码来处理细节。

要理解 UIKit 对象如何配合您的自定代码来工作,需要理解一下组成 iOS 应用程序的对象。图 1 显示 iOS 应用程序中最常见的对象,表 1 描述每个对象的角色。从框图中,您可以看到,iOS 应用程序是围绕“模型-视图-控制器”设计模式来组织的。此模式将模型中的数据对象,从用来显示该数据的视图中分离出来。这种分离使得随着需要来交换视图成为可能,从而提高了代码重用性,这在创建通用应用程序时特别有用(即可以同时在 iPad 和 iPhone 上运行的应用程序)。

图 1  iOS 应用程序中的关键对象
表 1  iOS 应用程序中的对象角色

对象

说明

UIApplication 对象

您基本上按原样使用 UIApplication 对象,就是说,不对它进行子类化。此控制器对象管理应用程序事件循环,并协调其他高级的应用程序行为。由您定制的应用程序级的逻辑,存在于应用程序的委托对象中,并与此对象紧密合作。

应用程序委托对象

应用程序委托是在应用程序启动时,创建的一个自定对象,通常由 UIApplicationMain 函数创建。此对象的主要工作,是处理应用程序内部的状态转换。例如,此对象负责启动时的初始化,并负责处理进入背景和从背景出来的转换。

在 iOS 5 和更高版本中,您可以使用应用程序委托,来处理其他与应用程序相关的事件。Xcode 项目模板将应用程序委托声明为 UIResponder 的子类。如果 UIApplication 对象不处理事件,它会将事件分派给应用程序的委托,以进行处理。

文稿和数据模型对象

数据模型对象储存应用程序的内容,是您的应用程序专有的。例如,银行业务应用程序,可能储存包含金融交易的数据库;而绘图应用程序,则可能储存图像对象,甚至储存创建该图像的绘图命令序列。(就绘图命令来说,图像对象仍是一个数据对象,因为它只是图像数据的容器。)

应用程序还可以使用文稿对象(UIDocument 的自定子类),来管理其数据模型对象中的一部分或全部。文稿对象不是必需的,但它们提供了一种便利的方式,对属于单个文件或文件包中的数据进行分组。有关文稿的更多信息,请参阅“定义基于文稿的数据模型”。

视图控制器对象

视图控制器对象管理应用程序内容在屏幕上的呈现。视图控制器管理单个视图及其分视图。呈现时,视图控制器将视图安装到应用程序的窗口中,使它们显示出来。

UIViewController 类是所有视图控制器对象的基础类。它提供了一些默认功能,用于载入视图、呈现视图和旋转视图,以响应设备的旋转以及几个其他标准的系统行为。UIKit 和其他框架定义附加的视图控制器类,来实现标准系统界面,如图像挑选器、标签栏界面和导航界面。

UIWindow 对象

UIWindow 对象协调一个或多个视图在屏幕上的呈现。大多数应用程序只有一个窗口,用于在主屏幕上呈现内容,但应用程序可能会有另外一个窗口,将内容显示在外接显示器上。

要更改您的应用程序的内容,需使用视图控制器,来更改在对应窗口中显示的视图。您不会把窗口本身替换。

除了充当视图的宿主以外,窗口还配合 UIApplication 对象工作,将事件传送到视图和视图控制器。

视图、控制和层对象

视图和控制将应用程序的内容直观地呈现出来。视图是一种对象,将内容绘制在指定的矩形区域内,并响应该区域的事件。控制是一类专门的视图,负责实施常见的界面对象,如按钮、文本栏和切换开关。

UIKit 框架提供标准的视图,用于呈现许多类型的内容。通过直接将 UIView(或它的子类)子类化,您还可以定义自己的自定视图。

除了包括视图和控制以外,应用程序还可以将 Core Animation 层并入其视图和控制分层结构中。层对象实际是代表视觉内容的数据对象。视图在幕后大量使用层对象,来渲染其内容。您还可以将自定的层对象,添加到界面,以实施复杂的动画和其他类型的复杂视觉效果。

iOS 应用程序之间的区别,在于所管理的数据(和相应的业务逻辑),以及如何将数据呈现给用户。大多数与 UIKit 对象的交互,并不是替您定义应用程序,而是让它的行为纳入规范。例如,您的应用程序委托的方法,让您知道应用程序的状态何时改变,以便您的自定代码可以适当地作出响应。

数据模型

应用程序的数据模型,由数据结构以及业务逻辑组成,业务逻辑是让数据保持一致状态所必要的。不要把数据模型的设计,脱离应用程序的用户界面来进行;但是,数据模型对象的实现,应该是分开的,而不依赖于特定视图或视图控制器存在与否。保持数据与用户界面分开,有助于实现通用应用程序(可在 iPad 和 iPhone 双平台上运行的应用程序),也让重复使用部分代码变得容易。

如果您尚未定义数据模型,iOS 框架会就这方面为您提供帮助。以下部分重点描述了一些技术,让您使用定义特定类型的数据模型。

定义自定数据模型

定义自定数据模型时,请创建自定对象,来表示任何高级结构。但对简单的数据类型,大可利用系统提供的对象。Foundation 框架提供了许多对象(大部分对象已在表 2 中列出),以面向对象的方式管理字符串、数字以及其他类型的简单数据。使用这些对象,比定义新的对象要好,因为节省时间,而且许多系统例程要求使用内建的对象。

表 2  Foundation 框架中的数据类

数据

说明

字符串和文本

NSString (NSMutableString)

NSAttributedString (NSMutableAttributedString)

iOS 中的字符串是基于 Unicode 的。字符串类提供了支持,可以用多种方式创建和操控字符串。带属性的字符串类,支持样式化的文本,须配合 Core Text 使用。

数字

NSNumber

NSDecimalNumber

NSIndexPath

当您要把数值储存在集 (collection) 中时,请使用数字对象。NSNumber 类可以表示整数值、浮点数值、Boolean 值和 char 值。NSIndexPath 类储存数字序列,通常用来指定层次列表中的多层选择。

原始字节

NSData (NSMutableData)

NSValue

每当需要储存原始字节流时,请使用数据对象。数据对象也常用来以归档形式储存对象。NSValue 类通常已经扩展(使用类别),用来归档常见数据类型,如点和矩形。

日期和时间

NSDate

NSDateComponents

使用日期对象来储存时间戳、日历日期,以及其他时间相关的信息。

URL

NSURL

除了指向网络资源这一传统用途以外,iOS 中的 URL 还是储存文件路径的首选方式。NSURL 类甚至支持获取和设定文件相关的属性。

NSArray (NSMutableArray)

NSDictionary (NSMutableDictionary)

NSIndexSet (NSMutableIndexSet)

NSOrderedSet (NSMutableOrderedSet)

NSSet (NSMutableSet)

使用集将相关的对象聚合在一个地方。Foundation 框架提供了几种不同类型的集类。

除了与数据相关的对象以外,还有一些其他的数据类型,通常由 iOS 框架用来管理常见类型的数据。鼓励您在自定的对象中使用这些数据类型,来表示相似类型的数据。

  • NSInteger/NSUInteger——有符号的标量和无符号的整数的抽象,基于架构定义了整数的大小。

  • NSRange——一种结构,用来定义一个序列的连续部分。例如,您可以使用范围定义字符串中被选定的字符。

  • NSTimeInterval——给定时间间隔中的秒数(整数和小数)。

  • CGPoint——x 和 y 坐标值,定义一个位置。

  • CGSize——坐标值,定义一组水平和垂直的范围。

  • CGRect——坐标值,定义一个矩形的区域。

当然,在定义自定对象时,您总是可以将标量值直接并入到类的实现中。实际上,自定数据对象的成员变量,可以混用标量和对象类型。列表 1 是一个类定义的示例,用于一组图片的集。此示例中的类,包含一个图像数组,以及在这个数组中代表所选项目的索引列表。该类还包含集标题名称的字符串,以及一个标量 Boolean 变量,指示当前的集是否可编辑。

列表 1  自定数据对象的定义

@interface PictureCollection :NSObject
 
@property (nonatomic, copy) NSString * title;
@property (nonatomic) BOOL editable;
@property (nonatomic, readonly) NSOrderedSet* pictures;
@property (nonatomic) NSMutableIndexSet *selection;
 
// Method definitions...
 
@end

要考虑自定对象上的撤销操作如何处理。支持撤销,意味着能够干净利落地复原对您的对象所做的更改。如果您的对象包含复杂的业务逻辑,就需要将此逻辑分解,赋予容易撤销的方式。以下是在自定对象中实现撤销支持的一些技巧:

  • 定义您需要的方法,以确定对您的对象的修改是对称的。例如,如果您定义了一个方法来添加项目,请确定也有一个方法,用相似的方式来移除项目。

  • 把您的业务逻辑,从您用来修改成员变量值的代码中分解出来。

  • 对于多步骤操作,请使用现有的 NSUndoManager 对象,将步骤组合起来。

使用 Core Data 定义结构化数据模型

Core Data 是一种模式驱动的 (schema-driven) 对象图管理和持久性框架。从根本上讲,Core Data 帮助您将模型对象(以“模型-视图-控制器”设计模式的方式)存储到一个文件中,然后再将它们取回来。这类似于归档,但 Core Data 远不止那些。

  • Core Data 提供了一个基础结构,来管理对模型对象所做的修改。它让您自动支持撤销和重做,以及维持对象之间的相互关系。

  • 它允许您在任何给定的时间内,仅将模型对象的子集保存在内存中,这对于 iOS 应用程序是非常重要的。

  • 它使用模式来描述模型对象。在基于 GUI 的编辑器中,您定义模型类的主要功能(包括模型类之间的关系)。模式“免费”提供了丰富的基本功能,包括设定默认值和验证属性值。

  • 它允许您维护编辑对象的不相交集合。不相交集合很实用,例如,您想要允许用户在一个视图中进行可被放弃的编辑,而不影响另一个视图中显示的数据。

  • 它具有的基础结构,用于数据储存版本管理和迁移。版本管理可让您轻松地将旧版本的用户文件升级到当前版本。

  • 它允许您在 iCloud 中储存数据,然后从多个设备访问数据。

定义基于文稿的数据模型

基于文稿的数据模型,可以便捷地用于管理被应用程序写入磁盘的文件。这种类型的数据模型,让您使用文稿对象来表示磁盘上单个文件(或文件包)的内容。该文稿对象负责读写文件的内容,并配合应用程序的视图控制器工作,将文稿的内容显示在屏幕上。文稿对象的传统用途,是管理包含用户数据的文件。例如,创建并管理文本文件的应用程序,会使用单独的文稿对象管理每个文本文件。但是,您可以将文稿对象用于专用的应用程序数据(也通过文件来支持)。

图 2 说明了应用程序的数据模型中的文稿、文件和对象之间的典型关系。在少数例外情况下,每个文稿是自包含的,不直接与其他文稿交互。文稿管理单一的文件(或文件包),并在内存中标识在该文件中找到的任何数据。因为每个文件的内容是唯一的,与每个文稿相关联的数据结构,也是唯一的。

图 2  使用文稿来管理文件的内容

您使用 UIDocument 类来实现 iOS 应用程序中的文稿对象。此类提供基本的基础结构,以处理文稿的文件管理各方面所需。UIDocument 的其他好处包括:

  • 它支持在合适的时间自动存储文稿内容。

  • 它为储存在 iCloud 中的文稿处理所需要的文件协调。它还为解决版本冲突提供了钩子 (hook)。

  • 它为撤销操作提供了支持。

为了实施应用程序的文稿所要求的特定行为,您必须创建 UIDocument 的子类。

用户界面

每个 iOS 应用程序,都至少有一个窗口和一个视图,来显示它的内容。窗口提供了在其中显示内容的区域,是 UIWindow 类的实例。视图负责管理内容的绘制(并处理触摸事件),是 UIView 类的实例。对于使用视图对象构建的界面而言,应用程序的窗口自然包含多个视图对象。对于使用 OpenGL ES 构建的界面而言,通常只有一个视图,并使用该视图来渲染内容。

视图控制器也在应用程序的用户界面中,扮演很重要的角色。视图控制器是 UIViewController 类的实例,负责管理一组视图,以及那些视图与应用程序的其他部分之间的交互。因为 iOS 应用程序显示内容的空间很有限,视图控制器也提供了所需要的基础结构,从一个视图控制器中撤出视图,以另一个视图控制器中的视图来替换。因此,视图控制器是您实施各种类型的内容转换的方式。

您要经常将一个视图控制器对象,作为自包含的单元来看。它处理其自身视图的创建和销毁,处理其视图在屏幕上的显示,并协调视图和应用程序中的其他对象之间的交互。

使用 UIKit 视图构建界面

使用 UIKit 视图进行绘图的应用程序很容易创建,因为您可以快速组装一个基本界面。UIKit 框架提供了许多类型的视图,来帮助呈现和组织数据。控制是一种特殊类型的视图,它提供了一个内建机制,每当用户执行了合适的操作,即执行自定代码。例如,点按按钮,导致与该按钮关联的操作方法被调用。

基于 UIKit 视图的界面的好处是,您可以使用 Interface Builder(内建在 Xcode 中的可视化界面编辑器)以图形方式组装它们。Interface Builder 提供了一个资源库,包含了标准视图、控制,以及构建界面所需要的其他对象。将对象从资源库拖出并放置在工作前台,而且可以根据需要随意进行安放。接着可使用检查器配置对象,然后再将它们存储到串联图或 nib 文件中。以图形方式组装界面的过程,比编写同等代码要快得多,您立即看到结果,而不需要先生成并运行应用程序。

图 3 显示了应用程序的基本结构,其界面仅使用视图对象构建。在此实例中,主视图利用了窗口的可见区域(状态条除外),提供一个简单的白色背景。主视图还包含三个分视图:一个图像视图、一个文本视图和一个按钮。应用程序使用那些分视图,来向用户显示内容并响应交互。层次中的所有视图,都是由一个视图控制器对象来管理。

图 3  使用视图对象构建界面

在典型的基于视图的应用程序中,您使用视图控制器对象来协调屏幕视图。应用程序总是有一个视图控制器,负责在屏幕上显示所有内容。该视图控制器具有一个内容视图,其本身可能包含其他视图。有些视图控制器也可以用作容器,供其他视图控制器提供的内容使用。例如,分离视图控制器会并排显示两个视图控制器的内容。

使用视图和 OpenGL ES 构建界面

游戏以及其他需要很高帧速率或复杂绘图功能的应用程序,可以将专门为 OpenGL ES 绘图而设计的视图添加到其视图层次中。最简单的 OpenGL ES 应用程序类型,具有一个窗口对象、一个视图(用于 OpenGL ES 绘图),以及一个视图控制器,来管理内容的显示和旋转。更复杂的应用程序,可以混用 OpenGL ES 视图和 UIKit 视图,来实施其界面。

图 4 显示了一个应用程序的配置,该程序只使用一个 OpenGL ES 视图来绘制其界面。不像 UIKit 视图,OpenGL ES 视图是由一种不同类型的层对象(CAEAGLLayer 对象)来支持的,而不是基于视图的应用程序所使用的标准层。CAEAGLLayer 对象提供了 OpenGL ES 可以将内容渲染在其中的绘图表面。要管理绘图环境,应用程序也创建 EAGLContext 对象,并将该对象连同视图储存下来,使它容易取回。

图 4  使用 OpenGL ES 构建界面

应用程序包

当您生成 iOS 应用程序时,Xcode 将它捆绑成一个包。捆绑包 (bundle) 是文件系统中的一个目录,它将相关资源成组在一个地方。一个 iOS 应用程序捆绑包中,含有其可执行文件和支持资源文件(如应用程序图标、图像文件和已本地化的内容)。表 3 列出了一个典型的 iOS 应用程序捆绑包(名为 MyApp,用于演示目的)的内容。此示例仅用于图解目的。此表中列出的某些文件,可能不会出现在您自己的应用程序捆绑包中。

表 3  一个典型的应用程序捆绑包

文件

示例

说明

应用程序可执行文件

MyApp

可执行文件包含应用程序的已编译代码。将应用程序名称去掉 .app 扩展名之后,就是其可执行文件的名称。

此文件是必需的。

信息属性列表文件

Info.plist

Info.plist 文件包含应用程序的配置数据。系统使用此数据来确定如何与应用程序交互。

此文件是必需的,而且名称必须为 Info.plist

应用程序图标

Icon.png

Icon@2x.png

Icon-Small.png

Icon-Small@2x.png

应用程序图标用来在设备的主屏幕上表示应用程序。其他图标由系统用在合适的地方。其文件名中含有 @2x 的图标,专用于配备 Retina 显示屏的设备。

应用程序图标是必需的。

启动画面

Default.png

Default-Portrait.png

Default-Landscape.png

应用程序启动时,系统将此文件用作临时背景。一旦应用程序准备好显示其用户界面,它就会被移走。

至少需要一个启动画面。

串联图文件(或 nib 文件)

MainBoard.storyboard

串联图含有视图和视图控制器,应用程序通过它们,将内容呈现在屏幕上。串联图中的视图,是根据显示它们的视图控制器来组织的。串联图也确定一组视图的转换(称为过渡),将用户从一组视图带到另一组。

当您创建项目时,主串联图文件的名称由 Xcode 设定。您可以通过给 Info.plist 文件中的 NSMainStoryboardFile 键指定其他值,来更改该名称。使用 nib 文件(而不是串联图)的应用程序,可以使用 NSMainNibFile 键替换 NSMainStoryboardFile 键,并使用该键来指定其主 nib 文件。

使用串联图不是硬性规定,但建议您还是使用它。

临时分发图标

iTunesArtwork

如果您准备临时分发应用程序,请准备好一个 512 x 512 像素版本的应用程序图标。此图标正常由 App Store 从您提交到 iTunes Connect 的材料中提供。然而,由于应用程序是临时分发的,没有通过 App Store 审批,您的图标必须存在于捆绑包中。iTunes 使用此图标来表示您的应用程序。(如果您准备用那种方式来分发应用程序,则指定的文件就应该与您已提交到 App Store 的那个文件一样。)

此图标的文件名必须是 iTunesArtwork,不包括文件扩展名。此文件对于临时分发是必需的,其他情况下属可选。

设置捆绑包

Settings.bundle

如果想要通过“设置”应用程序,来展示自定的应用程序偏好设置,您必须准备好一个设置捆绑包 (settings bundle)。此捆绑包含有属性列表数据,还包含定义应用程序偏好设置的其他资源文件。“设置”应用程序使用此捆绑包中的信息,来组装所需要的界面元素。

此捆绑包是可选的。

非本地化资源文件

sun.png

mydata.plist

非本地化资源包括应用程序所使用的图像、声音文件、影片和自定数据文件之类的资源。所有这些文件,都应该放置在应用程序捆绑包的顶层位置。

本地化资源的子目录

en.lproj

fr.lproj

es.lproj

本地化资源必须放置在语言特定的项目目录中,目录的名称由 ISO 639-1 语言缩写和 .lproj 后缀组成。(例如,en.lprojfr.lprojes.lproj 目录,含有本地化为英文、法文和西班牙文的资源。)

iOS 应用程序应该是国际化的,对于所支持的每一种语言,都有一个语言.lproj 目录。除了为应用程序的自定资源提供本地化版本以外,您还可以本地化其图标、启动画面和“设置”图标,方法是将同名文件放入特定语言的项目目录中。