65.9K
CodeProject 正在变化。 阅读更多。
Home

iOS 5 开发者手册:构建您的第一个项目

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (3投票s)

2011年12月8日

CPOL

98分钟阅读

viewsIcon

57715

这是《iOS 5 开发者食谱:iOS 程序员的核心概念和基本食谱,第三版》的章节摘录

ShowCover.jpg

Erica Sadun
由 Addison-Wesley Professional 出版
ISBN-10: 0-321-75426-3
ISBN-13: 978-0-321-75426-4

Xcode 借助其令人兴奋的代码编辑器和测试工具套件,帮助您精心制作 iOS SDK 应用程序。本章将向您介绍使用 Xcode 构建项目的基本知识。您将了解如何构建一个简单的 Hello World 项目,在模拟器中编译和测试它,然后学习如何为设备编译和部署。您还将发现一些基本的调试工具,并通过它们的用法以及一些关于方便的编译器指令的提示。本章还将介绍如何提交到 App Store 并执行用于测试的临时分发。完成本章后,您将从头到尾了解应用程序创建过程,并在此过程中学到宝贵的技巧。

创建新项目

如果一开始就深入 SDK 编程而没有救生索似乎令人望而生畏,请放心。Xcode 简化了入门过程。它提供了预配置的项目,您可以在探索 SDK 时轻松调整。这些项目提供了完全可用的骨架。您所需要做的就是添加一些自定义功能,使您的应用程序独一无二。

要开始,请启动 Xcode 4 并选择“文件”>“新建项目” (Command-Shift-N)。“新建项目”模板窗口(请参阅图 3-1)将打开,允许您选择以下应用程序样式之一以开始。这些项目样式旨在匹配 iOS 最常见的开发模式。您的选择如下:

图 3-1
Xcode 新项目模板选择窗口。随着 Apple 不断发展其设计工具,Xcode 界面将会改变。
  • 基于文档的应用程序——旨在与 iCloud 配合使用,文档模板为围绕无处不在的元素构建应用程序创建了一个起点。
  • 主从应用程序——通常基于列表和表格,主从应用程序允许用户深入了解分层界面。这些应用程序提供了一个树形结构的界面选项集合,每个选项都会滑动到一个新屏幕,或者在 iPad 的情况下,显示在一个单独的详细视图中。导航屏幕顶部的栏包含一个集成的“返回”按钮,允许用户单击即可返回到上一个屏幕。在 iPad 上,分屏视图会自动适应设备方向。在横向模式下,两个视图同时显示;在纵向模式下,显示详细视图,并且选择选项通过基于导航栏的弹出窗口显示。
  • OpenGL 游戏——使用 OpenGL ES 编程时,您所需要的只是一个绘图视图和一个提供动画心跳的计时器。OpenGL 游戏模板提供了这些元素,让您可以在其之上构建 OpenGL ES 图形。
  • 基于页面的应用程序——通过选择此基于页面视图控制器的模板来创建书籍风格的应用程序。页面视图控制器是 iOS 5 中新增的功能,它允许用户使用熟悉的基于触摸的手势导航电子“书”。数据源客户端将视图控制器提供给应用程序,而委托允许应用程序响应基于手势的导航和方向更新。
  • 单视图应用程序——这个简单的模板为主要视图控制器提供了一个基本起点,为 iPhone 和 iPad 分发都提供了故事板。当您寻找一个以主要视图为中心而不是需要专用容器样式(如导航控制器、标签栏控制器、分屏视图控制器、页面视图控制器等)的应用程序时,选择这种样式。
  • 标签式应用程序——Apple 的 iPod 和 YouTube 应用程序提供了标签栏应用程序的典型示例。在这些应用程序中,用户可以通过点击应用程序底部栏中的按钮从一系列并行屏幕中进行选择。例如,YouTube 应用程序允许您从特色视频、最多观看、书签和搜索窗格中进行选择,每个都通过一个标签按钮访问。标签式应用程序模板提供了一个骨架,您可以扩展它以添加窗格及其内容。尽管您可以在 Xcode 中选择 iPhone 或 iPad 作为目标产品,但 Apple 鼓励您避免在 iPad 上创建标签栏式应用程序。iPad 宽敞的屏幕空间提供了足够的空间,您无需使用标签栏和导航应用程序的约定来折叠您的主界面。
  • 实用工具应用程序——旨在成为最简单的应用程序样式,实用工具应用程序模板创建了一个两面单视图演示,就像您在股票和天气应用程序中看到的那样。该模板提供了一个主视图和一个翻转视图,您可以轻松自定义。此应用程序模板在 iPhone 上使用简单的翻转到另一面演示。在 iPad 上,它提供了一个链接到信息栏按钮项的弹出窗口。实用工具应用程序在高度专注时效果最佳。翻转视图或弹出窗口通常用于应用内设置,而不是主界面功能集的扩展。
  • 空应用程序——基于窗口的应用程序本质上提供了与单视图应用程序相同的模板,但没有故事板。您将获得一个应用程序委托和一个可自定义的窗口,仅此而已。选择此模板的一个优点是,如果您更喜欢完全从头开始构建 iPhone 应用程序,它相对容易自定义。

注意 - Apple 在 iOS 参考库提供示例代码和教程。在线访问该库:http://developer.apple.com/library/ios/navigation/index.html;您必须使用您的开发者凭据才能访问其内容。除了示例代码,您还将找到发行说明、技术说明、入门指南、编码操作方法等。其中许多资源也可以通过 Xcode 内置的文档浏览器直接访问。

以模板方式构建 Hello World

Xcode 的预配置模板为创建 Hello World 风格的示例应用程序提供了最简单的途径。在以下步骤中,您将创建一个新项目,对其进行编辑以显示“Hello World”,并在 iOS 模拟器上运行它。在构建您的第一个 Xcode 项目时,您将发现一些关键的开发路径。

创建新项目

安装 iOS SDK 后,启动 Xcode。关闭 Xcode 欢迎页面;它是显示“欢迎使用 Xcode”并提供“创建新 Xcode 项目”等选项的窗口。在关闭此窗口之前,它会一直出现,直到您取消选中“在 Xcode 启动时显示此窗口”。此后,您可以通过“窗口”>“欢迎使用 Xcode” (Command-Shift-1) 访问该页面。

要创建一个新项目,选择“文件”>“新建”>“新建项目” (Command-Shift-N)。这将打开图 3-1所示的模板选择窗口。默认情况下,模板选择窗口嵌入在一个大的新窗口中,该窗口称为“工作区”。工作区将 Xcode 的所有编辑和检查器功能嵌入到一个窗口中。

图 3-1的左栏包含三个 iPhone 项目类别。它们是应用程序(即您在图 3-1中看到的屏幕)、框架与库(用于创建静态 Cocoa Touch 库模块)以及其他(最初包含一个单一的空项目样式)。

选择“应用程序”>“单视图应用程序”,然后单击“下一步”。Xcode 会打开一个“为您的新项目选择选项:”屏幕,如图 3-2所示。输入 Hello World 作为项目名称,并设置公司标识符(例如,com.sadun)。公司标识符通常使用反向域名命名。新的应用程序标识符会显示在其下方,以浅灰色文本显示。在我的情况下,这是 com.sadun.Hello-World。输入一个可选的类前缀。Xcode 将其用于预置模板类。例如,如果您输入 ES,Xcode 会创建 ESAppDelegate.h 和 .m 文件。从“设备系列”弹出窗口中选择“通用”。保持“使用故事板”选中。保持“包含单元测试”未选中。单击“下一步”。

图 3-2
设置公司标识符后,Xcode 会在后续运行中应用您的设置。这有助于您避免之前 Xcode 版本中最烦人的功能之一——不得不记住为每个项目编辑您的设置,而不是“com.yourcompany”。

选择保存新项目的位置(例如桌面)并点击“保存”。一个新的 Hello World Xcode 工作区将打开(参见图 3-3)。此项目包含设计一个新的通用应用程序所需的所有文件,该应用程序以一个主窗口为中心。文件被分组到文件夹中,并列在左侧窗格中,该窗格称为“导航器”。您的新项目默认被选中。其项目和目标设置显示在右侧编辑器窗格中。此项目设置编辑器在功能上类似于早期 Xcode 版本中的目标信息窗格,但具有许多改进的功能。您看到的第一个编辑器窗格允许您选择方向支持并设置应用程序图像。

图 3-3
这个全新的 Hello World 项目是通过选择一个可用模板创建的。在旧项目中,您也可能会在此屏幕上看到一个“现代化”按钮。

随意探索新项目中的文件。打开组(它们看起来像文件夹,但只是项目的组织辅助工具)以显示其内容,然后选择任何文件以在编辑器中查看它。要一次性显示所有文件夹,请在没有子文件显示时,Option-点击主项目列表(在本例中为“Hello World”)旁边的箭头。如果文件正在显示,请Option-点击两次。第一次点击会隐藏所有子文件;第二次点击会显示它们。

Xcode 4 的编辑器支持代码、属性列表、图像(仅显示)和 Interface Builder (IB) 文件。例如,如果单击 MainWindow_iPad.xib,将打开一个 IB 编辑器窗格。这与 Xcode 3 发生了巨大变化,在 Xcode 3 中,Interface Builder 是一个独立的程序。

正如图 3-3所示,Xcode 的 GUI 相较于其 3.x 版本,发生了巨大的变化。无论您是 iOS 开发新手,还是从早期 SDK 迁移而来,都非常值得探索 Xcode 工作区及其组件。从更集成的单窗口工作区到 Interface Builder 迁移到主 Xcode 应用程序中,Xcode 4 中有许多新功能等待着您。

Xcode 工作区介绍

尽管从图 3-3中看不出来,但标准的 Xcode 项目窗口由三个主要部分组成。您可以通过单击窗口右上角的“实用工具”按钮来最好地看到这一点。这是从右数第二个按钮,看起来像一个带有较小深色矩形的白色矩形。它是一组七个按钮的一部分,分为三组按钮(标记为“编辑器”),然后是三组按钮(标记为“视图”),然后是一个按钮(标记为“组织器”)。继续单击它以显示编辑器右侧的“实用工具”部分。您可能需要在显示“实用工具”部分后调整工作区大小。

图 3-4显示了展开的工作区。它由三个区域和一个工具栏组成。从左到右,这些区域包括导航器窗格(允许您浏览项目组件)、中间的编辑器窗格(提供文件的编辑器和查看器)以及右侧的实用工具区域(提供检查器和库访问)。

图 3-4
Xcode 工作区由几个区域组成,如图所示。

当程序运行时,编辑器底部会出现一个可选的调试窗格。您可以通过单击编辑器左下角的调试器显示按钮,或者通过单击 Xcode 窗口右上角三个视图按钮的中间来显示和隐藏它。显示按钮是一个带有向上(“显示”)或向下(“隐藏”)三角形的小矩形。视图按钮是一个矩形,底部有一个较深的嵌入矩形。

窗口顶部工具栏的中心会出现一个小小的中央活动视图。它呈浅蓝色,位于窗口标题正下方。此视图显示项目的当前状态和任何正在进行的活动,例如构建代码或正在进行的搜索。它看起来很像您在 iTunes 中看到的活动视图。应用程序运行、停止和断点控件位于活动视图的左侧。

控制工作区

工作区工具栏右侧的七个按钮允许您选择查看工作区的方式。从左到右,这些按钮如下:

  • 编辑器按钮——这三个编辑器按钮控制代码在中央编辑器窗口中的显示方式。您的选择是标准、助手和版本
    • 标准编辑器(Command-Return)显示一个源代码窗格。
    • 助手(Command-Option-Return)允许您将查看器分成两部分,在辅助窗格中提供上下文增强文件。助手可以自动查找文件并显示文件对应项(例如,在查看 MyClass.m 时显示 MyClass.h)、超类或子类文件等。助手是 Xcode 4 绝对出色的功能。使用“视图”>“助手布局”子菜单自定义您的助手布局。
    • 版本编辑器(Command-Shift-Option-Return)允许您比较同一文件的两个版本,以便您发现差异并查看不同提交之间随时间的变化。
    • 视图按钮——这三个按钮允许您隐藏和显示图 3-4中出现的导航器(左)、调试(中)和实用工具(右)窗格。当所有三个都隐藏时,只显示中央编辑器窗格。这样做提供了一个看起来简单的编辑器窗口,但可以快速访问项目控件。您也可以双击导航器中的文件以在新窗口中打开它们,同时隐藏其他窗格。
    • 组织器按钮——组织器按钮看起来像一个带有嵌入式小矩形的小窗口,它提供一键式访问 Xcode 组织器窗口。组织器将在本章后面讨论,它为您的移动设备控件、文档、项目组织等提供了一个单一来源。您还可以通过选择“窗口”>“组织器”或按键盘上的 Command-Shift-2 来访问组织器。

    注意 - 双击导航器中列出的任何文件,可以在单独的编辑器窗口中打开它。默认情况下,这会隐藏顶部工具栏。通过选择“视图”>“显示工具栏”来恢复它。默认情况下,此菜单项没有快捷方式,但您可以使用 Quickeys 等第三方实用程序或通过偏好设置的键绑定窗格添加一个。

    Xcode 导航器

    Xcode 窗口的左侧窗格不仅列出项目和文件夹。它还处理更多内容。它被称为“导航器区域”,它允许您导航工作区中有关项目的信息。Xcode 4 提供了七个专门的导航器。每个导航器都组织信息,以便您可以浏览它。这些导航器通过导航器窗格顶部的选项卡按钮访问。Xcode 4 导航器包括以下项目:

    • 项目导航器(Command-1)列出构成您项目的组和文件。选择一个文件会在中央窗格中打开该文件。显示的编辑器类型取决于所选文件。代码文件(.h、.m 等)打开一个代码编辑器。属性列表文件,例如您的 Info.plist,打开一个属性列表编辑器。接口文件(.storyboard 和 .xib 文件)直接在 Xcode 项目窗口中以 Interface Builder (IB) 编辑器打开。这与早期版本的 Xcode 不同,在早期版本中,IB 是一个独立的程序,不属于 Xcode。
    • 符号导航器(Command-2)枚举您项目中使用的类、函数和其他符号。选择一个符号会打开声明头文件,这样您就可以立即查找元素的定义方式。位于编辑器另一侧右侧区域的“实用工具”>“符号”(快速帮助)检查器窗格,通过为任何选定的符号(无论您是从符号导航器中选择还是从源代码编辑器中选择)提供即时上下文文档,与符号导航器同步工作。

    注意 - 当“实用工具”>“符号”(快速帮助)检查器隐藏时,您可以 Option-单击导航器中的任何符号或代码编辑器中的任何文本,以弹出 Xcode 4 快速帮助窗口,其中包含与“实用工具”>“符号”窗格中相同的上下文文档。使用 Option-双击以在组织器的文档窗口中打开该项目。快速帮助弹出窗口的右上角出现两个按钮。小书本按钮链接到任何现有文档。带有“h”的文件图标链接到声明头文件。

    • 搜索导航器(Command-3)提供了一种在项目中查找文本的简便方法。您可以在工作区(包括已添加到工作区的任何项目)和关联的框架中搜索该文本的实例。在文本字段中输入时,从文本字段弹出菜单中选择您想要使用的搜索方法。搜索字段左侧的一个简单弹出窗口还允许您使用查找和替换功能。您不限于通过此搜索导航器进行搜索。您还可以通过 Command-F(编辑 > 查找 > ...)在任何基于文本的编辑器中进行搜索。
    • 注意 - 搜索导航器中搜索字段左侧的小放大镜图标在控制您搜索哪些文档方面起着重要作用。单击放大镜并选择“查找选项”以显示将搜索短语与源代码匹配的选项。

    • 问题导航器(Command-4)提供在构建请求期间发现的警告和错误的列表。使用此窗格选择每个问题并在中央代码编辑器中突出显示其问题。
    • 调试导航器(Command-5)提供了一种在执行期间检查线程和堆栈的方法。当您选择一个项目时,编辑器将立即跳转到源代码或反汇编窗口,在那里您可以看到当前的执行点。
    • 断点导航器(Command-6)提供项目中调试断点的全局列表。单击任何断点以在编辑器中查看文件。
    • 日志导航器(Command-7)允许您将构建结果作为历史记录查看。单击任何过去的构建以在中央编辑器窗格中查看构建日志。

    Xcode 实用工具窗格

    右侧的实用工具窗格中出现上下文相关的帮助器窗格。与左侧的导航器一样,实用工具区域可以根据需要显示或隐藏。此区域由两部分组成:顶部是检查器窗格;底部是库窗格。检查器提供有关当前选择的信息和自定义选项。例如,当您在嵌入式 Interface Builder 中选择一个标签(一个 UILabel 实例)时,您可以使用检查器设置其对齐方式、背景颜色或尺寸。库提供您可以合并到项目中的预构建组件,并且可以包括媒体和代码片段。

    这两个窗格都以与导航器窗格类似的方式提供了一组选项卡式子窗格。按钮显示在每个窗格的顶部。检查器按钮会根据当前选择的上下文进行更新。例如,为 UILabel 对象出现的对象属性和连接检查器在源代码编辑器中处理文本时不会出现。这是因为这些 Interface Builder 风格的检查器在处理源代码时没有意义。实用工具窗格会更新以匹配中央编辑器中当前选定的项目。

    检查器快捷键是 Command-Option 加上一个数字,从 1 和 2 开始,分别用于文件(Command-Option-1)和快速帮助(Command-Option-2)检查器。它们从那里开始按数字递增,具体取决于可用的检查器实用程序窗格。通常,IB 风格的检查器包括身份(Command-Option-3)、属性(Command-Option-4)、大小(Command-Option-5)和连接(Command-Option-6)。Xcode 3.x 用户应该注意,窗格顺序与 3.x Interface Builder 中使用的有所不同,并且旧的键盘快捷键不再适用。

    库使用 Command-Control-Option 快捷键与数字组合。库窗格提供对文件模板(Command-Control-Option-1)、代码片段(Command-Control-Option-2)、对象(Command-Control-Option-3)和媒体(Command-Control-Option-4)的访问。您可以将自己的自定义元素添加到代码片段库中,以便轻松访问重复的代码模式。

    通过键入 Command-Control-Option-0 隐藏或显示“实用工具”部分。

    编辑器窗口

    编辑器窗口包含一个主要空间,用于显示内容。在此空间上方,您会找到一个“跳转栏”。此栏通过任何分组级别简化了查找其他文件。每个类似路径的元素都提供一个弹出菜单,可快速访问这些元素。跳转栏出现在许多 Xcode 4 角色中。它们都以类似方式工作,并引入了一种在结构化系统中移动的层次结构方式。

    跳转栏最左侧的一个特殊菜单项,一个带有八个小矩形的按钮,可以帮助您找到与当前显示项相关的文件。选项包括代码对应项(.m/.h 文件对)、超类、子类、同级、类别、包含文件等。这是一个非常强大的菜单,您不应忽视。

    编辑器窗口的中心空间提供了 Quick Look 技术,可以预览您将添加到 Xcode 项目中或需要支持该项目的几乎任何类型的内容。这意味着您不仅可以将内容查看器用于直接编码材料,还可以审查与项目开发相关的 PDF 和 Keynote 演示文稿等。

    使用多个编辑器窗口

    您可能希望同时使用多个编辑器窗口。为此,您可以创建一个新的工作区窗口,在一个窗口中使用选项卡,或者分离一个浮动编辑器。窗口和选项卡都允许您在各种编辑器和文件之间快速切换。

    要打开新的编辑器窗口而不带走整个工作区,请双击任何文件名。一个浮动编辑器窗口将出现在您的工作区上方,其中包含该文件的内容。

    要创建一个新的工作区窗口,请选择“文件”>“新建”>“新建窗口” (Command-Shift-T)。新窗口包含与原始工作区相同的项目。在一个窗口或选项卡中对文件进行的更改将反映到其他窗口或选项卡中的同一文件。

    注意 - 要在源代码编辑窗口中添加行号,请打开“偏好设置”(Xcode > 偏好设置,Command-,)。选择“文本编辑”窗格并勾选“行号”。

    要使用选项卡,请选择“视图”>“显示选项卡栏”。这将在主工具栏和其下方的窗格之间显示一个工作区选项卡栏。使用“文件”>“新建选项卡” (Command-T) 创建新选项卡,或在选项卡栏中右键单击 (Control-单击) 并从上下文弹出菜单中选择“新建选项卡”。或者,在导航器中单击文件名时按 Shift-Option,然后单击右上角的“+”按钮以在新选项卡中打开文件。

    Xcode 选项卡遵循 Apple 的标准,因此如果您习惯使用 Safari 选项卡,它们在 Xcode 中的工作方式也类似。要从键盘在选项卡之间导航,请使用 Command-Shift-[ 向左移动,使用 Command-Shift-] 向右移动。单击 + 以向窗口添加新选项卡。您可以将选项卡拉出到它们自己的窗口中,也可以通过将选项卡添加到选项卡栏来将选项卡拖放到现有窗口中。

    Cocoa Samurai 博客 (cocoasamurai.blogspot.com) 创建了许多 Xcode 4 键盘快捷键参考指南。这些信息图表托管在 github (github.com/Machx/Xcode-Keyboard-Shortcuts) 上,提供了您可以在 Xcode 中导航所用按键组合的详尽指南。

    注意 - Xcode 为单个会话提供完整的撤消支持。只要您在同一会话中执行操作,甚至可以撤消先前的保存。也就是说,您不能关闭项目,重新打开它,然后恢复在项目关闭之前所做的更改。

    项目回顾

    当 Xcode 创建您的新项目时,它会填充所有您构建第一个 iOS 应用程序所需的基本元素和框架。您在此项目中看到的项目包括:

    • 框架 > Foundation 和 Core Graphics 框架——这些基本框架使您能够构建 iPhone 应用程序,并且与 OS X 上发现的框架类似。
    • 框架 > UIKit 框架——此框架提供 iOS 特定的用户界面 API,是开发可在 iPhone 屏幕上查看和交互的应用程序的关键。
    • 产品 > HelloWorld.app——此占位符用于存储您完成的应用程序。与 Macintosh 类似,iPhone 应用程序是捆绑包,由存储在中央文件夹中的许多项目组成。
    • 支持文件 > HelloWorld-Info.plist——此文件向 iPhone 系统描述您的应用程序,并允许您指定其可执行文件、其应用程序标识符和其他关键功能。它的工作方式与 Mac 上的 Info.plist 文件相同。属性列表的可本地化字符串可以在“支持文件”>“InfoPlist.strings”文件中找到。
    • MainStoryboard_iPhone.storyboard 和 MainStoryboard_iPad.storyboard——这些 Interface Builder 文件为每个平台创建了一个最少填充的 GUI。您将修改即将进行的演练。
    • [前缀]AppDelegate.h、[前缀]AppDelegate.m、[前缀]ViewController.h、[前缀]ViewController.m、main.m——这些文件包含一个粗略的 Objective-C 骨架,您可以自定义和扩展它以创建您的应用程序。这些文件使用的前缀在“新建项目选项”屏幕中设置。随意浏览代码,但您不会在即将进行的演练中编辑这些文件。相反,您将使用 Xcode 设置它们的方式,并将您的修改限制在 Interface Builder 故事板中。

    注意 - 要在 Xcode 4 中向您的项目添加框架,请在项目导航器中选择您的蓝色项目文件。在中央编辑器窗格中,单击最左侧列中的“TARGETS”>“Target Name”。单击“构建阶段”并打开“Link Binary With Libraries”展开三角形。单击“+”按钮,导航到您希望添加的框架(您会在“设备”文件夹下找到标准框架),选择它,然后单击“添加”。一个选项窗格将打开。取消选中“Copy items into destination group’s folder”(如果需要),确保您的目标保持选中状态,然后单击“完成”。要移除一个框架,只需选择它并单击“-”。

    打开 iPhone 故事板

    在项目导航器中找到 MainStoryboard_iPhone.storyboard 文件。故事板存储 Interface Builder 布局,并可以包含单个应用程序的所有屏幕(称为“场景”)。选择故事板文件以在中央编辑器中打开它,以便您可以开始编辑该文件。您将在编辑器的背景中看到网格图案,并在窗口左侧看到场景列表。此列表最初由单个 Hello World 视图控制器场景组成。该场景出现在网格区域中,由一个空视图在顶部和其下方关联的对象停靠区组成。图 3-5显示了它的样子。

    图 3-5
    iPhone 故事板的 Interface Builder 窗口。每个故事板场景下方浮动着一个小的停靠栏,提供对与其视图关联的对象的访问。

    停靠区中的两个图标代表您正在编辑的界面的元素。右侧是视图的所有者——在本例中是其视图控制器。它代表附加到视图的视图控制器。

    视图控制器没有视觉呈现。它们管理视图,但它们本身不显示任何内容。每个视图控制器都有一个名为“view”的属性,该属性设置为负责提供实际屏幕呈现的 UIView。在此处,该视图显示在停靠区上方。您可以通过选择它并打开“视图”>“实用工具”>“显示身份检查器”来了解有关控制器的更多信息。观察检查器中列出的类(ESViewController 或类似)。

    停靠区中的视图控制器元素称为“代理”。代理在 IB 中扮演角色,但它所代表的对象(视图控制器)本身并未嵌入到 .storyboard 档案中。此代理代表加载并拥有视图的对象。

    要查看项目如何相互连接,请选择“视图”>“实用工具”>“显示连接检查器”。您会看到一个名为“view”的出口。将鼠标悬停在此出口上,视图会变暗。还会出现一个小工具提示(显示“View”)。这是因为您的视图控制器的 view 出口已连接到该视图。出口在 IB 术语中表示“实例变量”。

    另一个图标,位于停靠栏左侧位置的图标,称为 First Responder。它看起来像一个带有数字 1 的深橙色立方体。与视图控制器一样,它是一个代理对象。它表示当前正在响应用户触摸的屏幕对象。在应用程序的生命周期中,第一响应者会随着用户与屏幕的交互而改变。例如,想象一个表单。当用户触摸该表单中的每个文本字段时,该字段会变为活动状态并承担第一响应者的角色。有时您希望允许界面元素(例如按钮和开关)控制任何作为第一响应者的项目。在 Interface Builder 中连接到此代理可以实现这一点。

    编辑视图

    要开始自定义,请点击大的白色视图。默认情况下,此视图是空的,尽管顶部显示状态栏。由您来自定义此视图并添加任何内容。为此,您需要依赖“实用工具”区域中的两个工具:Interface Builder 对象库和检查器。

    选择“视图”>“实用工具”>“显示属性检查器” (Command-Option-4)。“属性检查器”允许您调整当前选定对象的属性——在本例中,即您正在编辑的视图。在检查器中,找到“视图”>“背景列表”及其颜色样本。单击样本并从“颜色”调色板中选择一种新颜色。您正在编辑的视图会自动更新其背景颜色。

    接下来,通过选择底部窗格顶部的第三个图标来打开对象库。或者,选择“视图”>“实用工具”>“显示对象库” (Command-Control-Option-3)。此库(参见图 3-6)显示了您可以在 IB 文件中使用的预构建 Cocoa Touch 元素列表。这些元素包括视图控制器等抽象元素以及按钮和滑块等可视化组件。在库底部的搜索字段中输入 label。将标签从中间窗格拖放到您的窗口中。(或者,双击库中的标签。这会自动将该项添加到您的窗口中。)

    图 3-6
    Interface Builder 对象库。

    将其拖到视图后,双击标签并将文字从“Label”更改为“Hello World”。您还可以在窗口中移动标签以适应您的审美偏好,或者在“尺寸检查器”中设置其位置。“属性检查器”允许您设置字体和大小,以及文本颜色。您可能需要调整标签大小以适应新的大小。取消选择“自动缩小”,并注意有两个地方可以设置字体大小。主检查器中的字段设置标签的最小字体大小。字体弹出菜单设置期望字体大小。

    使用“文件”>“保存” (Command-S) 保存您的项目。您现在已经使用此内容自定义了您的 iPhone 窗口。

    接下来,自定义 iPad 界面。返回“项目导航器”并选择 MainStoryboard_iPad.storyboard。您会注意到 iPad 的显示比 iPhone 大得多。即使在相对较大的屏幕上,您也可能无法一次看到整个 iPad 界面。

    Interface Builder 允许您双击网格背景以将显示缩小到更易于管理的尺寸,但在此模式下您无法进行编辑。您还可以使用编辑器窗口右下角的新缩放/缩小按钮。许多开发人员发现,投资一个大的垂直显示器而不是水平显示器,以便更好地在 IB 中进行 iPad 编辑是值得的。

    像以前一样,更改视图的背景颜色,添加一个标签(也许是“Hello World on iPad”),并调整其字体和位置。再次,保存您的项目(文件 > 保存,Command-S)。

    运行您的应用程序

    在窗口左上角的“开始/停止”按钮右侧的工作区工具栏中找到弹出菜单。从该弹出菜单中选择“Hello World”>“iPhone 模拟器”。这告诉 Xcode 为基于 Macintosh 的 iPhone 模拟器编译您的项目。如果出现多个模拟器选项,请选择最新的 SDK(即 5.3 而不是 5.0)。

    点击运行按钮(默认情况下它看起来像一个“播放”按钮)或输入 Command-R,然后等待 Xcode 开始工作。编译需要几秒钟,然后 Xcode 会自动启动模拟器,安装您的项目并运行它。图 3-7显示了结果,Hello World 应用程序在模拟器上运行。

    图 3-7
    自定义的 Hello World 应用程序在模拟器上运行。

    在 iPhone 模拟器上测试应用程序后,单击停止按钮(运行按钮右侧),然后使用 iPad 模拟器测试应用程序。从弹出菜单中选择“Hello World”>“iPad 模拟器”,然后再次单击运行按钮。

    使用模拟器

    iOS SDK 模拟器使得在 Macintosh 上测试应用程序成为可能,它使用户可以在实际设备上执行许多相同的操作。由于 Macintosh 不是手持式基于触摸的移动系统,因此您必须使用菜单、键盘快捷键以及鼠标或触控板来模拟 iPhone 风格的交互。表 3-1 显示了如何通过模拟器执行这些任务。

    表 3-1  iPhone 操作的模拟器等效项

    操作 模拟器等效
    选择设备 使用“硬件”>“设备”模拟原始 iPhone、Retina iPhone 或 iPad 风格的设备。固件版本可通过“硬件”>“版本”选择。
    旋转设备 硬件 > 向左旋转 (Command-左箭头) 和 硬件 > 向右旋转 (Command-右箭头)。模拟器支持所有四种主要界面方向:竖屏、横屏向左、横屏向右和竖屏倒置。您无法模拟面朝上或面朝下方向。
    摇晃设备 硬件 > 摇晃手势 (Command-Control-Z)。这会使用运动事件模拟摇晃,但不模拟其他加速度计动作。我鼓励您避免构建依赖用户摇晃设备的应用程序,无论该功能看起来多么酷。
    按下主页键 点击模拟器屏幕上的“主页”按钮或选择“硬件”>“主页” (Command-Shift-H)。
    锁定设备 硬件 > 锁定 (Command-L)。
    点击和双击 使用鼠标单击,单次或双击均可。
    在键盘上敲击 点击虚拟键盘或在 Mac 键盘上输入。为了便于测试,您可以使用许多 Mac 风格的快捷键,包括 Command-A、Command-C 等。
    拖动、滑动和轻扫 用鼠标点击、拖动并释放。拖动的速度决定了动作。对于轻扫,拖动非常快。
    捏合放大或缩小 按住键盘上的 Option 键。当出现两个点时,将它们相互靠近或远离。按住 Shift 键以移动点的原点。
    内存不足 硬件 > 模拟内存警告。这允许您模拟低内存条件,让您测试应用程序的响应方式。
    进行中电话(仅视觉显示) 硬件 > 切换通话状态栏。在 iPhone 上,您可以在通话时运行应用程序。通话期间,通话栏会出现在屏幕顶部。
    连接键盘 通过选择“硬件”>“模拟硬件键盘”来模拟检测蓝牙或坞站硬件键盘。
    连接电视输出电缆 选择“硬件”>“电视输出”以模拟 VGA 或 HDMI 电缆连接到坞站连接器。使用此功能测试您的外部屏幕代码,特别是捕获屏幕连接和断开连接通知。一个浮动窗口显示模拟输出。
    更改缩放 通过选择“窗口”>“缩放”来更改模拟器的放大倍数。选择 100%、75% 和 50%。
    模拟打印机 选择“文件”>“打开打印机模拟器”以使用 AirPrint 测试您的软件。您还可以使用此模拟器测试从设备打印。打印输出将在预览中打开。
    截取屏幕截图 选择“文件”>“保存屏幕截图” (Command-S) 或使用“编辑”>“复制屏幕” (Command-Control-C) 复制屏幕。
    设置模拟位置 使用“调试”>“位置”菜单来模拟 iPhone 的使用位置。您可以选择(固定)自定义位置、Apple 总部、Apple Store、城市骑行/跑步,或沿着高速公路驾车。
    减慢动画速度 选择“调试”>“切换慢动画”以让您更好地在更长的时间内查看动画。使用此功能发现动画中的不一致和缺陷。
    突出显示潜在的渲染问题点 使用四个“调试”>“颜色”选项来定位潜在的显示问题。这些项目通过菜单选择切换开关,包括混合图层、复制图像、未对齐图像和屏幕外渲染的元素。
    重置模拟器 选择“iOS 模拟器”>“重置内容和设置”以将模拟器恢复到其“出厂设置”的原始状态,删除所有当前应用程序、设置和用户数据。

    模拟器:幕后

    由于模拟器在 Macintosh 上运行,Xcode 会为 Intel 芯片编译模拟应用程序。您的应用程序基本上在模拟器内的 Macintosh 上本地运行,使用一组基于 Intel 的框架,这些框架镜像了随 iOS 安装到实际设备上的框架。这些框架的模拟器版本通常位于 Xcode 开发者目录中,在 /Developer/Platforms/iPhoneSimulator.platform/Developer/ SDKs/iPhoneSimulator5.0.sdk/System/Library 或类似位置。实际位置会因您使用的 SDK 版本以及您安装 SDK 的位置而异。/Developer 文件夹是默认位置,但您可以轻松覆盖它。

    您可以在您的主目录的 Library/Application Support 文件夹中找到您的应用程序。它们存储在 iPhone Simulator/ 中,位于许多特定于固件的文件夹之一,例如 3.1.2/、4.2/ 和 6.1/,位于 User/Applications/ 下。访问这些文件夹以了解应用程序如何部署到 iPhone 是很有帮助的;这些 User/ Applications/ 文件夹模拟设备安装。其他有趣的开发文件夹包括:

    • /Developer/Platforms/iPhoneSimulator.platform/Developer/ Applications——实际 iPhone 模拟器应用程序的默认位置。
    • /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/ iPhoneSimulatorX.X.sdk/Applications——模拟器内置应用程序的位置,包括 Mobile Safari、通讯录等。将 X.X 替换为固件版本。
    • /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/ iPhoneSimulator5.0.sdk/System/Library/Frameworks——您可以从应用程序链接到的 Cocoa Touch 框架的位置。
    • /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/ Templates/Project Templates/Application——图 3-1中显示的各个项目模板的位置。
    • ~/Library/MobileDevice/Provisioning Profiles——存储您的 iPhone Portal 配置文件的文件夹。
    • ~/Library/Developer/Xcode/Archives——存储使用 Xcode 中的“构建”>“构建并归档”选项构建的归档文件的文件夹。归档应用程序将显示在您的 Xcode 组织器中,在那里可以对其进行验证、共享和提交到 iTunes Connect。
    • ~/Library/Developer/Xcode/DerivedData——构建和日志文件夹。
    • ~/Library/Developer/Xcode/Snapshots——项目版本控制快照。
    • ~/Library/Developer/Shared/Xcode/Screenshots/——用于组织器截取的屏幕截图的文件夹。
    • ~/Library/Developer/Shared/Project Templates/——将自定义模板添加到此文件夹,使其显示在“新建项目”屏幕中。
    • ~/Library/MobileDevice/Software Images——存储可安装到您设备上的 iOS 固件文件(.ipsw 文件)的文件夹。
    • ~/Library/Application Support/MobileSync/Backup——iTunes 存储 iPhone、iPod touch 和 iPad 备份文件的文件夹。

    注意 - 应用程序归档允许您将应用程序共享为 .ipa 文件。它们还允许您运行 iTunes Connect 用于确认应用程序是否使用开发证书正确签名(在提交应用程序之前或提交应用程序时)的相同验证测试。

    每个应用程序都存储在单独的沙盒中。沙盒的名称是随机的,使用唯一的代码(由 CFUUIDCreateString() 生成)。您可以压缩沙盒文件夹并在 Macintosh 之间共享。另一台 Macintosh 需要安装 Xcode 才能访问模拟器及其框架。

    每个沙盒名称都隐藏了它所托管的应用程序,因此您必须窥视内部才能看到里面有什么。在内部,您会找到应用程序捆绑包(例如 HelloWorld.app)、一个 Documents 文件夹、一个 Library 文件夹和一个临时 (/tmp) 文件夹。运行时,每个应用程序都限制访问这些本地文件夹。它们不能像 Macintosh 上的应用程序那样使用主用户库。

    除了 Library/Caches 文件夹,应用程序的 Documents 和 Library 文件夹中的所有内容在部署到设备时都会由 iTunes 备份。tmp 文件夹不会由 iTunes 备份。使用 Caches 文件夹存储需要持久化的大型、不断变化的应用程序支持数据文件。使用 tmp 文件夹存储 iOS 可以在应用程序启动之间处置的材料。

    如果您想清理应用程序的沙盒文件夹,可以在模拟器未运行时直接删除文件。您还可以通过选择模拟器本身的“iPhone 模拟器”>“重置内容和设置”来删除所有模拟器数据。这将删除应用程序、它们的沙盒以及任何影响模拟器运行的当前设置,例如非默认语言选择。

    或者,使用您在 iPhone 设备上习惯的“按住直到晃动”界面。在您按住任何图标几秒钟后,应用程序图标将开始晃动。进入此编辑模式后,您可以移动图标或按下角落的 X 图标以删除应用程序及其数据。按“主页”按钮退出编辑模式。

    尽管应用程序无法访问用户库文件夹,但您可以。如果您想编辑模拟器的库,文件存储在您主目录的 Application Support 文件夹中的 iPhone Simulator/User/Library 文件夹中。编辑您的库可以让您测试依赖于地址簿的应用程序,例如。您可以将不同的地址簿 sqlitedb 文件加载到 Library/AddressBook 中,以少量或大量联系人测试您的源代码。

    注意 - iPhone 模拟器和 Mac OS X 使用独立的剪贴板。模拟器存储自己的剪贴板数据,这些数据是从 iOS 复制/粘贴调用中收集的。当您使用“编辑”>“粘贴” (Command-V) 时,模拟器会将 Mac 剪贴板中的文本粘贴到模拟器的剪贴板中。然后您可以使用模拟器的“编辑”菜单(在文本框中双击)将 iOS 剪贴板中的内容粘贴到模拟器应用程序中。

    共享模拟器应用程序

    当开发人员无法访问新硬件或测试版固件未广泛分发时,模拟器编译的应用程序提供了一种共享测试版本的重要方式。它们还可以支持在实际设备部署之前进行界面设计测试。尽管不适合进行完整的调试和最终用户可用性测试(参见第 1 章“iOS SDK 简介”),但模拟器版本在 iOS 应用程序生命周期中确实发挥着作用和目的。

    要共享应用程序,请将整个沙盒文件夹从一台 Macintosh 压缩,然后将其提取到另一台 Mac 的模拟器应用程序文件夹中。

    极简主义的 Hello World

    在探索 iOS SDK 的过程中,本着 Hello World 的精神,了解如何构建精简的应用程序很有帮助。也就是说,您应该知道如何完全从头开始构建应用程序,而无需五个源文件和两个界面文件。这里有一个演练,向您展示了这一点——一个非常基本的 Hello World,它反映了前面 Hello World 示例中显示的方法,但它只用一个文件,没有 .storyboard 或 xib 文件就完成了。

    首先在 Xcode 中创建一个新项目(文件 > 新建项目,Command-Shift-N)。选择“空应用程序”,单击“下一步”,输入 Hello World 作为产品名称,并根据需要设置您的公司标识符(我的是 com.sadun)。将设备系列设置为“通用”,取消选中“使用核心数据”,取消选中“包含单元测试”,然后单击“下一步”。将其保存到桌面。

    当项目窗口打开时,从项目导航器中选择两个 App Delegate 文件(.h 和 .m),然后单击删除或退格键以删除它们。在提示时选择“删除”(以前是“也移至废纸篓”)。

    打开 Hello World > 支持文件 > main.m 并将其内容替换为列表 3-1。源代码包含在本书的示例代码中(详情请参阅序言),因此您无需手动输入。

    列表 3-1  简化版 main.m

    #import <UIKit/UIKit.h>
    
    // Simple macro distinguishes iPhone from iPad 
    #define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)  
    @interface TestBedAppDelegate : NSObject <UIApplicationDelegate> 
    {
         UIWindow *window; 
    } 
    @end  
    
    @implementation TestBedAppDelegate - (UIViewController *) helloController 
    {
         UIViewController *vc = [[UIViewController alloc] init];
         vc.view.backgroundColor = [UIColor greenColor];
    
         // Add a basic label that says "Hello World"
         UILabel *label = [[UILabel alloc] initWithFrame:
             CGRectMake(0.0f, 0.0f, window.bounds.size.width, 80.0f)];
         label.text = @"Hello World";
         label.center = CGPointMake(CGRectGetMidX(window.bounds),
             CGRectGetMidY(window.bounds));
         label.textAlignment = UITextAlignmentCenter;
         label.font = [UIFont boldSystemFontOfSize: IS_IPHONE ? 32.0f : 64.0f];
         label.backgroundColor = [UIColor clearColor];
         [vc.view addSubview:label];
          return vc; 
    }  
    
    - (BOOL)application:(UIApplication *)application
         didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
    {
         window = [[UIWindow alloc] initWithFrame:
             [[UIScreen mainScreen] bounds]];
         window.rootViewController = [self helloController];
         [window makeKeyAndVisible];
         return YES; 
    } 
    @end  
    
    int main(int argc, char *argv[]) {
         @autoreleasepool {
             int retVal =
                 UIApplicationMain(argc, argv, nil, @"TestBedAppDelegate");
             return retVal;
         } 
    }

    那么这个应用程序是做什么的呢?它构建一个窗口,给背景着色,并添加一个显示“Hello World”的标签。换句话说,它做的与第一个 Hello World 示例完全相同,但它是手动完成的,没有使用 Interface Builder。

    应用程序在 main.m 中通过建立自动释放池并调用 UIApplicationMain() 开始。从那里,控制权传递给应用程序委托,该委托通过命名类作为调用的最后一个参数指定。这是构建非 Interface Builder 项目的关键点,也是许多新 iPhone 开发者遇到的难题。

    委托收到 application:didFinishLaunchingWithOptions: 消息后,会创建一个新窗口,查询设备的屏幕尺寸(边界)。它会创建一个新的视图控制器,将其分配为 rootViewController 属性,并将其显示出来,使其可见。使用设备的屏幕边界可确保主窗口的尺寸与设备匹配。对于较旧的 iPhone,窗口将占据 320·480 像素的区域;对于 iPhone 4 及更高版本,为 640·960 像素;对于前两代 iPad,为 768·1024 像素。

    helloController 方法通过为其背景着色和添加标签来初始化其视图控制器的视图。它使用 UI_USER_INTERFACE_IDIOM() 检测设备是 iPhone 还是 iPad,并相应地将标签的字体大小调整为 32 或 64 磅。在实际使用中,您可能需要执行其他特定于平台的调整,例如选择艺术品或设置布局选项。

    如您所见,布局标签需要几个步骤。它被创建,然后添加文本,居中,对齐,并修改其他功能。这些专业化选项中的每一个都定义了标签的视觉外观,这些步骤在 Interface Builder 中可以更容易、更直观地应用。列表 3-1 演示了您可以完全通过代码构建界面,但它显示了该代码如何迅速变得繁重和密集。

    在 Xcode 中,Interface Builder 属性检查器实现了相同的功能。检查器显示标签属性,提供交互式控件以选择左对齐、居中和右对齐等设置。在这里,对齐方式以编程方式设置为常量 UITextAlignmentCenter,背景颜色设置为透明,标签通过其 center 属性以编程方式移动到位。最终,手动和 Interface Builder 方法都做同样的事情,但在这里,程序员利用 SDK API 的特定知识来生成一系列等效命令。

    浏览 SDK API

    iOS SDK API 在 Xcode 内部有完整的文档和可访问性。选择“帮助”>“开发人员文档” (Command-Option-Shift-?) 以打开 Xcode 组织器 > 文档浏览器。窗口顶部栏将选中“文档”选项卡。其他选项卡包括 iPhone、存储库、项目和归档,每个选项卡都在组织 Xcode 资源方面发挥作用。

    您可以在此窗口中浏览的文档在 Xcode 的偏好设置中进行控制。通过选择“Xcode”>“偏好设置”(Command-,)>“文档”来打开这些偏好设置。使用“获取”按钮下载文档集。通过启用“自动检查并安装更新”来保持文档最新。

    在“开发者文档”组织器中,首先找到左侧区域顶部的三个按钮。从左到右,它们包括一个眼睛、一个放大镜和一本打开的书。眼睛链接到探索模式,让您查看所有可用的文档集。放大镜提供交互式搜索,因此您可以输入短语并在当前文档集中找到匹配项。打开的书链接到书签,您可以在其中存储指向您最常用文档的链接。

    选择中间的(放大镜)搜索按钮。在该按钮正下方的文本字段中找到另一个小放大镜。这个第二个放大镜旁边有一个显示三角形。单击该三角形并从弹出菜单中选择“显示查找选项”。这样做会在文本字段下方显示三个选项:匹配类型、文档集和语言。使用“文档集”弹出菜单隐藏除最新 iOS 文档集之外的所有内容。这会简化您的搜索结果,这样您就不会从您实际未使用的 SDK 版本中找到多个匹配项。

    在搜索字段中输入 UILabel 以查找与 UILabel 匹配的 API 结果,以及全文和标题匹配。结果列表中的第一个项目应链接到 iOS Library 版本的文档。请参阅主区域顶部的跳转栏以找到您正在查看的库。这应该显示类似“iOS Library > 用户体验 > 窗口和视图 > UILabel 类参考”的内容。UILabel 类参考(参见图 3-8)显示了标签的所有类方法、属性和实例方法,以及类的概览。

    图 3-8
    Apple 在 Xcode 内部提供完整的开发人员文档。

    Apple 基于 Xcode 的文档内容详尽且清晰。通过它,您可以即时访问完整的 SDK 参考。您无需离开 Xcode 即可查找所需的任何内容。当资料过时时,文档订阅系统可让您直接在 Xcode 中下载更新。

    Xcode 4 失去了 Xcode 3 中文档左侧出现的方便的类概览。顶部的跳转栏嵌入了相同的组织功能(即概览、任务、属性等)。如果您更喜欢以旧版开发者库概览的方式查看材料,请在类参考区域中右键单击并选择“在浏览器中打开页面”。图 3-9显示了基于浏览器的演示,其中有核心材料左侧有用的类一目了然的目录。

    图 3-9
    “目录”视图已不再在 Xcode 本身中可用,但可以通过“在浏览器中打开页面”访问。

    将 Interface Builder 文件转换为 Objective-C 等效项

    Adrian Kosmaczewski 提供了一个方便的开源实用工具,允许您将 Interface Builder 文件转换为 Objective-C 代码。借助它,您可以提取视觉设计的所有布局信息和属性,并查看如何手动编码。nib2objc 正如其名称所示。借助它,您可以生成考虑到类构造函数、方法调用等内容的转换代码。它适用于 .xib 和 .storyboard 文件,尽管一些较新的功能(如 segues)尚未公开;从底层看,这两种格式都只是 XML。

    列表 3-2 显示了在第一次演练中对 .xib 文件运行 nib2objc 的结果。将其与列表 3-1 中更简单(且不那么彻底)的手动版本进行比较。它执行的任务大致相同。它创建一个新标签,然后将标签添加到窗口中。但是,此转换实用工具公开了所有底层属性,而其中只有少数在列表 3-1 中进行了编辑。

    要查看原始 IB XML,请在 Text Edit 中打开故事板文件。在 HelloWorld 项目文件夹的 en.lproj 子文件夹中,从终端命令行发出 open -e 命令

    open -e MainStoryboard_iPad.storyboard

    注意 - nib2obj 托管在 http://github.com/akosma/nib2objc,并以“用它行善而非作恶”风格的许可证发布。

    列表 3-2  HelloWorldViewController.xib 转换为 Objective-C 后

    UIView *view3 = [[UIView alloc] initWithFrame:
         CGRectMake(0.0, 20.0, 320.0, 460.0)]; 
    view3.frame = CGRectMake(0.0, 20.0, 320.0, 460.0); 
    view3.alpha = 1.000; 
    view3.autoresizingMask =
         UIViewAutoresizingFlexibleRightMargin |
         UIViewAutoresizingFlexibleBottomMargin;
    view3.backgroundColor =
         [UIColor colorWithRed:0.963 green:1.000 blue:0.536 alpha:1.000];
    view3.clearsContextBeforeDrawing = YES; 
    view3.clipsToBounds = NO; view3.contentMode = UIViewContentModeScaleToFill; view3.hidden = NO; view3.multipleTouchEnabled = NO; view3.opaque = YES; view3.tag = 0; 
    view3.userInteractionEnabled = YES;  
    
    UILabel *view6 = [[UILabel alloc] initWithFrame:
         CGRectMake(72.0, 150.0, 175.0, 160.0)]; 
    view6.frame = CGRectMake(72.0, 150.0, 175.0, 160.0); 
    view6.adjustsFontSizeToFitWidth = YES; 
    view6.alpha = 1.000; view6.autoresizingMask =
         UIViewAutoresizingFlexibleLeftMargin |
         UIViewAutoresizingFlexibleRightMargin |
         UIViewAutoresizingFlexibleTopMargin |
         UIViewAutoresizingFlexibleBottomMargin; 
    view6.baselineAdjustment = UIBaselineAdjustmentAlignCenters; 
    view6.clearsContextBeforeDrawing = YES; 
    view6.clipsToBounds = YES; 
    view6.contentMode = UIViewContentModeLeft; v
    iew6.enabled = YES; view6.hidden = NO; 
    view6.lineBreakMode = UILineBreakModeTailTruncation; 
    view6.minimumFontSize = 10.000; 
    view6.multipleTouchEnabled = NO; 
    view6.numberOfLines = 1; view6.opaque = NO; 
    view6.shadowOffset = CGSizeMake(0.0, -1.0); 
    view6.tag = 0; view6.text = @"Hello World"; 
    view6.textAlignment = UITextAlignmentLeft; 
    view6.textColor = [UIColor colorWithRed:0.000 green:0.000 blue:0.000 alpha:1.000]; 
    view6.userInteractionEnabled = NO;  
    
    [view3 addSubview:view6]; 
    [view2 addSubview:view3];

    使用调试器

    Xcode 的集成调试器为 iPhone 应用程序开发提供了宝贵的工具。本演练将向您展示调试器所在的位置,并提供使用它进行程序调试的简单基础。在这些步骤中,您将了解如何设置断点以及如何使用调试器控制台检查程序详细信息。这些步骤假设您正在处理刚刚描述的第二个极简 Hello World 示例,并且项目窗口已打开并显示 main.m 文件。

    设置断点

    在 Hello World 项目的 main.m 文件中找到 helloController 方法。点击 Xcode 窗口最左侧列中,紧靠 label 赋值行的左侧。出现一个蓝色断点指示器(参见图 3-10)。深蓝色表示断点处于活动状态。点击一次停用——断点变为浅蓝色——再点击一次重新激活。

    图 3-10
    蓝色断点指示器出现在编辑器区域左侧的空白处。您可以在运行应用程序时通过单击调试器显示按钮,或者随时单击工作区窗口右上角三个视图按钮的中间来显示工作区底部的调试器。

    通过将断点拖出屏幕或右键单击它们来移除断点;通过单击列中任意代码行旁边来添加断点。添加后,您的断点将出现在工作区的断点导航器 (Command-6) 中。您可以从导航器中删除断点(选择,然后按 Delete 按钮),也可以在那里停用和重新激活它们。

    打开调试器

    编译应用程序(产品 > 构建,Command-B)并运行它(产品 > 运行,Command-R)。模拟器打开,显示一个黑屏,然后暂停。当执行遇到断点时,会自动中断。断点旁边出现一个绿色条,上面写着“线程 1:在断点 1 处停止。”

    在 Xcode 中,调试窗格会在您运行应用程序时自动出现。您可以通过单击工作区窗口右上角三个视图按钮的中间来手动显示或隐藏它;它看起来像一个底部为深色的矩形。当调试器显示时,您可以向上拖动其跳转栏(不是编辑器窗口顶部的那个,而是调试器顶部的那个)以提供更多空间来显示您的输出。

    调试器既提供了用于检查程序对象的图形前端,也提供了带有交互式调试器控制台的基于文本的日志区域。Xcode 提供了两个命令行调试器:gdb 和 lldb。LLDB 项目(托管在 https://llvm.net.cn)在标准 GNU 调试器 (gdb) 的基础上进行了扩展,提高了内存效率并集成了 Clang 编译器。

    通过编辑您的项目方案选择您希望使用的调试器,如图 3-11所示。从工作区窗口顶部工具栏左侧“运行”和“停止”按钮右侧的弹出菜单中选择“编辑方案”。(确保您选择的是弹出菜单的“Hello World”部分,而不是 iPhone 或 iPad 模拟器部分。)使用“信息”>“调试器”弹出菜单在 GDB 和 LLDB 之间切换。单击“确定”。

    图 3-11
    项目方案编辑器允许您选择首选的调试器。

    检查标签

    在断点处停止后,交互式调试器和调试器命令行允许您检查程序中的对象。使用 lldb,您可以通过在命令行输入 print-object label 或更简单地 po label 来查看标签。使用 printp 来打印非对象,例如整数值。

    (lldb) po label 
    (UILabel *) $3 = 0x06a3ded0 <UILabel: 0x6a3ded0; frame = (0 0; 320 80); 
    clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer: 0x6a3df40>>

    此时,标签的文本尚未设置,也尚未添加到视图控制器的视图中。您可以通过查看视图控制器的视图的子视图(当前为空数组)和标签的父视图(当前为 nil)来确认标签尚未添加到视图中。

     (lldb) po [[vc view] subviews] 
    (id) $4 = 0x06811e20 <__NSArrayI 0x6811e20>(  
    
    )  (lldb) po [label superview] 
    (id) $5 = 0x00000000 <nil> 
    (lldb)

    您也可以使用调试器左侧的检查器直接查看标签。找到 label 并点击其左侧的展开三角形以显示标签对象的属性。标签的 _text 字段设置为

    “单步进入”按钮出现在调试器跳转栏的左侧。它看起来像一个指向小黑线的向下箭头。点击它一次。文本赋值执行,绿色箭头向下移动一行。label.text 的摘要更新。它现在应该显示类似“Hello World (iPhone)”的内容。通过在命令行再次输入 po label 检查标签进行确认。标签已将其文本实例变量更新为 Hello World。

    (lldb) po label (UILabel *) $12 = 0x06a3ded0 <UILabel: 0x6a3ded0; frame = (0 0; 320 80); text = 'Hello World'; clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer: 0x6a3df40>>

    如果您真的想疯狂一把,您可以使用 pprint 在应用程序执行期间直接通过解释性调用来覆盖值。此调用将标签文本从“Hello World”更改为“Bye World”。它通过执行方括号内的项目,将空返回转换为整数,然后打印(无意义的)结果来实现。

    (lldb) p (int)[label setText:@"Bye World"] 
    (int) $13 = 117671936 
    (lldb) po label (UILabel *) $14 = 0x06a3ded0 <UILabel: 0x6a3ded0; frame = (0 0; 320 80); 
    text = 'Bye World'; 
    clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer: 
    0x6a3df40>>

    设置另一个断点

    您可以在调试会话期间设置其他断点。例如,在将文本对齐方式设置为居中的那行代码之后,在设置背景颜色的那行代码上添加第二个断点。只需单击 label.backgroundColor 旁边的空白区域,或您想设置断点的任何位置。

    通过检查标签的 textLabelFlags 来确认当前对齐方式设置为 0(默认值)——您必须打开 lldb 界面左侧列中的展开三角形才能看到这些标签属性。设置新断点后,单击“继续”按钮。它显示为一个右向三角形,其左侧有一条线。

    HelloWorld 继续执行,直到遇到下一个断点,然后停止。绿色箭头现在应该指向 backgroundColor 行,并且显式对齐标志从 0 更新为 1,因为该代码已经运行,改变了该变量的值。

    (lldb) p (int) [label textAlignment] 
    (int) $19 = 1

    您可以通过在左侧的调试检查器中选择项目,右键单击,然后从上下文弹出菜单中选择“打印描述”来进一步检查项目。这会将 description 方法发送到对象,并将其输出回显到控制台。

    注意 - 通过从左侧列中拖出断点或在“断点导航器”中删除它们来移除断点。

    通过发出 breakpoint list 命令列出您的断点。Lldb 会打印出所有活动断点的列表。

    (lldb) breakpoint list 
    Current breakpoints: 
    1: file ='main.m', line = 26, locations = 1, resolved = 1 
    baton: 0x11b2dd380   
    1.1: where = Hello World`-[TestBedAppDelegate helloController] + 365 at 
    main.m:26,
       address = 0x0000211d, resolved, hit count = 1  
    
    3: file ='main.m', line = 30, locations = 1, resolved = 1 
    baton: 0x12918d6c0
       3.1: where = Hello World`-[TestBedAppDelegate helloController] + 912 at main.m:30,
       address = 0x00002340, resolved, hit count = 0

    注意 - 访问 LLVM 网站了解有关设置和控制断点的更多信息。官方 lldb 教程位于 lldb.llvm.org/tutorial.html

    回溯

    调试窗口的底部窗格提供基于文本的调试器输出,可以镜像其他窗格的结果。例如,打开调试导航器并按线程查看应用程序,展开线程 1 的跟踪详细信息。这提供了执行轨迹,显示了调用了哪些函数和方法,以及以何种顺序将您带到应用程序的当前点。

    接下来,在文本调试器提示符处键入 backtracebt,以查看与该导航器中显示的相同跟踪。在第二个断点处停止后,回溯应该显示您接近(例如,main.m 中的源代码第 26 行)。您将在跟踪的开头看到此行号,而时间上更靠后的项则出现在跟踪的末尾。这与调试导航器中显示的视图相反,在调试导航器中,最近的调用出现在窗格的顶部。

    控制台

    这个底部的基于文本的调试器也称为控制台。在标准调试模式下运行或使用模拟器时,printfNSLogCFShow 消息默认发送到此窗格。您可以通过向上或向下调整跳转栏以及拖动调试器左右部分之间的调整栏来调整控制台的大小。如果您愿意,可以使用调试器右上角的显示/隐藏按钮。三个按钮让您可以隐藏控制台,显示控制台和视觉调试器,或者只显示控制台。这三个按钮的左侧是一个“清除”按钮。点击此按钮可以清除任何现有的控制台文本。

    要测试控制台日志记录,请在将标签添加为窗口子视图之后,在您的代码中添加一行 NSLog(@"Hello World!");。移除任何现有断点,然后编译并在模拟器中运行应用程序。日志消息将显示在“调试”区域的控制台窗格中。控制台在应用程序的每次执行过程中都会保留一个消息运行日志。您可以在应用程序运行时根据需要手动清除日志。

    添加简单调试跟踪

    如果您不害怕编辑项目的 .pch 文件,可以为调试版本添加简单的跟踪。编辑文件以添加以下宏定义

    #ifdef DEBUG
         #define DebugLog(...) NSLog(@"%s (%d) %@", __PRETTY_FUNCTION__, __LINE__,
         [NSString stringWithFormat:__VA_ARGS__]) 
    #else
         #define DebugLog(...) 
    #endif

    内存管理

    iOS 不提供垃圾回收。它依赖于引用计数内存管理系统。新的 LLVM ARC 扩展引入了自动引用计数,让编译器为您处理许多管理问题。ARC 自动化了对象的保留和释放,简化了开发。这并不意味着您不必担心内存

    • 即使有 ARC,您仍然需要负责释放那些会造成低内存状况的资源。如果您持有大量多媒体资产,如视频、音频和图像,即使在 ARC 编译的应用程序中,也可能会耗尽内存。
    • 许多开发人员继续使用手动保留/释放 (MRR) 开发,特别是为了避免重构关键生产代码。使用 MRR 意味着您必须控制该代码中对象的创建、保留和释放时间,因为 ARC 不会为您处理这些问题。
    • ARC 不会自动扩展到 Core Foundation 和其他基于 C 的类代码。即使 CF 类是 Toll-Free Bridged 的,ARC 也不会接管它们的实例,直到它们被桥接到 Objective-C 世界中。

    作为开发者,您必须制定策略来应对低内存情况。使用太多内存,iPhone 会警告您的应用程序委托和 UIViewController。委托会收到 applicationDidReceiveMemoryWarning: 回调;视图控制器会收到 didReceiveMemoryWarning。如果继续使用太多内存,iPhone 会终止您的应用程序,让用户回到 iOS 主屏幕。正如 Apple 反复指出的那样,这可能不是您希望用户获得的体验,并且您的应用程序将无法通过 App Store 的审核。

    您必须在程序中仔细管理内存,并在内存不足的情况下释放内存。低内存通常由两个问题之一引起:分配无法访问或重复使用的内存块的泄漏,以及同时持有过多数据。即使在较新的 iOS 设备(如 iPad 2)上,您的应用程序也必须在操作系统施加的任何内存限制内正常运行。

    Objective-C 中的每个对象都以基于整数的保留计数创建。只要该保留计数保持在 1 或更高,对象就不会被释放。该规则适用于 ARC 代码,也适用于 MRR。作为开发人员,您有责任实施策略,确保对象在您不再使用时被释放。

    每个使用 allocnewcopy 构建的对象都以保留值 1 开始。无论是使用 ARC 还是 MRR 进行开发,如果您在不将计数减少到 0 的情况下失去对对象的访问,则该丢失的对象会造成内存泄漏(即,已分配但无法恢复的内存)。以下代码会泄漏一个数组

    NSArray *leakyArray = [NSArray arrayWithObjects:@"Hello", @"World", nil]; 
    CFArrayRef leakyRef = (__bridge_retained CFArrayRef) leakyArray; 
    leakyRef = nil;

    食谱:使用 Instruments 检测内存泄漏

    Instruments 在调试应用程序方面发挥着重要作用。它提供了一套工具,让您能够监控和评估性能。例如,它的内存泄漏检测功能可让您跟踪、识别和解决程序中的内存泄漏。配方 3-1 展示了一个应用程序,它会按需创建两种类型的泄漏:一种是使用 CF 桥接但未正确释放内存而创建的,另一种是引入了一个强引用循环,该循环在其方法终止时无法通过 ARC 解决。

    要查看 Instruments 的实际运行情况,请加载配方 3-1 的示例项目。在工作区顶部工具栏中最左侧的弹出菜单中选择一个模拟器选项作为目标,就在“运行”和“停止”按钮的右侧。然后,按住“运行”按钮直到出现图 3-12 所示的弹出菜单。选择“Profile”,然后同意 Xcode 可能抛出的任何障碍(如果有),例如停止任何当前正在运行的应用程序等。

    图 3-12
    从“运行”按钮的弹出菜单中选择“Profile”。

    Instruments 启动并要求您选择一个跟踪模板。选择“iOS Simulator > Leaks”,然后点击“Profile”。Instruments 会打开一个新的分析窗口,在模拟器中启动应用程序,并开始运行。点击 Instruments 窗口左上角的“停止”按钮。您需要进行一些调整。

    在左侧列中,在各个 Instruments 跟踪下方,您会看到一个标有“Allocations”的项。它位于滑块下方和堆快照分析上方。这是一个弹出菜单,右侧的箭头表示。使用弹出菜单将“Allocations”更改为“Leaks”。

    选择“Leaks”后,第一项现在是“Snapshots”。将“Snapshot Interval”从 10 秒更改为 1 秒。这让您能够“实时”查看更新;即使如此,也要耐心。Instruments 在快照期间检测泄漏,执行快照后会有轻微延迟。

    您现在可以开始新的跟踪了。点击“Record”。应用程序会在模拟器中重新启动。Instruments 和模拟器都运行后,点击标题栏中的两个按钮之一来泄漏内存。

    • “CF Bridging”按钮泄漏一个简单的 16 字节 NSArray
    • “Retain Cycle”按钮泄漏两个通过保留循环相互连接的 16 字节 NSArray 对象,总计 32 字节。

    一旦您点击窗口顶部的“Leaks”跟踪行,内存泄漏就会在 Instruments 中显示为橙色标记,其大小按泄漏的大小缩放。泄漏块窗格会出现在窗口底部,如 图 3-13 所示。

    图 3-13
    Instruments 跟踪由您的代码无法寻址或恢复的内存块创建的泄漏。

    图 3-13 中所示的跟踪呈现了两个泄漏事件。第一个橙色标记对应于点击“Retain Cycle”按钮;第二个对应于“CF Bridging”。第一个泄漏的负责框架显示为 leakArrayRetainCycle 方法。堆栈跟踪出现在视图右侧的扩展详细信息窗格中。此窗格通过 Instruments 窗口顶部工具栏中三个视图按钮最右侧的一个来显示或隐藏。我的“Hello World”代码被标记为这两个泄漏的负责库,这让我进一步认识到泄漏的内存起源于我的代码。

    注意 - 在处理可能的保留循环时,使用窗口中央的跳转栏(在 图 3-13 中,四分之一的正方形后面跟着“Leaks”一词)选择“Cycles”。这是一个 Apple 仍在发展的功能。在编写本书期间(即测试版阶段),它的功能较少,崩溃较多。希望 Apple 会在 iOS 5 测试版正式发布之前完成对这一潜在宝贵反馈的完善。

    配方 3-1  创建程序化泄漏

    - (void) leakArrayRetainCycle {
         NSMutableArray *array1 = [NSMutableArray array];
         NSMutableArray *array2 = [NSMutableArray array];
         [array1 addObject:array2];
         [array2 addObject:array1]; 
    }  
    
    - (void) leakArrayCFBridge 
    {
         NSArray *array = [NSArray arrayWithObjects:
             @"Hello", @"World", nil];
         CFArrayRef leakyRef = (__bridge_retained CFArrayRef) array;
         leakyRef = NULL; 
    }

    获取本配方代码 - 要获取本配方使用的代码,请访问 https://github.com/erica/iOS-5-Cookbook,或者如果您已下载包含本书所有示例代码的磁盘映像,请转到第 3 章的文件夹并打开本配方的项目。

    配方:使用 Instruments 监控缓存对象分配

    当您一次加载过多数据时,也可能会出现内存不足的情况。当您使用图像、音频或 PDF 等内存密集型资源时,在程序中保留所有内容可能会导致问题。一种名为缓存的策略允许您延迟加载,直到实际需要资源,并在系统需要时释放该内存。

    最简单的方法是使用 NSMutableDictionary 对象构建缓存。基本的对象缓存工作方式如下:当查询时,缓存会检查请求的对象是否已加载。如果尚未加载,缓存会根据对象名称发送加载请求。对象加载方法可能会从本地或 Web 检索数据。数据加载后,缓存会将新信息存储在内存中以便快速调用。

    此代码执行缓存职责的第一部分。它会延迟将新数据加载到内存中,直到该数据被明确请求。(在实际应用中,您可能希望对数据进行类型化并返回特定类的对象,而不是使用通用的 id 类型。)

    - (id) retrieveObjectNamed: (NSString *) someKey {
         id object = [self.myCache objectForKey:someKey];
         if (!object)
         {
             object = [self loadObjectNamed:someKey];
             [self.myCache setObject:object forKey:someKey];
         }
         return object;
    }

    缓存的第二个职责是在应用程序遇到低内存条件时清除自身。对于基于字典的缓存,您所要做的就是删除对象。当下一次检索请求到来时,缓存可以重新加载请求的对象。

    - (void) respondToMemoryWarning 
    {
         [self.myCache removeAllObjects]; 
    }

    结合延迟加载和内存触发的清除,缓存能够以内存友好的方式运行。一旦对象加载到内存中,它们就可以被使用和重用,而无需加载延迟。然而,当内存紧张时,缓存会尽其所能释放运行应用程序所需的资源。

    模拟低内存条件

    模拟器的一个功能允许您测试应用程序如何响应低内存条件。选择“Hardware > Simulate Memory Warning”会向您的应用程序委托和视图控制器发送调用,要求它们释放不需要的内存。Instruments 允许您实时查看内存分配,可以监控这些释放。它确保您的应用程序在出现警告时正确处理。使用 Instruments,您可以测试本章前面讨论的内存策略,例如缓存。

    配方 3-2 创建了一个基本的对象缓存。此缓存不从 Web 或文件中检索数据,而是构建空的 NSData 对象来模拟实际用例。当内存警告到来时,如 图 3-14 所示,缓存会通过释放其数据来响应。

    图 3-14
    Instruments 帮助监控对象分配,让您能够在内存警告期间测试您的释放策略。

    此处显示的阶梯模式表示在使用 Instrument 的 Allocations 分析器时按下“Consume”按钮创建的四次内存分配。之后,模拟器发出了内存警告。作为响应,缓存通过释放其存储的图像完成了任务。内存随后回落到之前的水平。

    Instruments 允许您保存跟踪数据,显示应用程序随时间的性能。停止跟踪,然后选择“File > Save”以创建新的跟踪文件。通过比较运行,您可以评估应用程序不同版本之间性能和内存管理的变化。

    一些 SDK 对象会根据需要自动缓存和释放。UIImage imageNamed: 方法以这种方式检索和缓存图像,UINib nibWithNibName:bundle: 也是如此,它将 NIB 预加载到内存缓存中以加快加载速度。当内存不足时,这些类会清空其缓存以释放内存供其他用途。

    Recipe 3-2  Object Cache Demo 
    @implementation ObjectCache 
    @synthesize myCache, allocationSize;
    // Return a new cache + (ObjectCache *) cache 
    {
         return [[ObjectCache alloc] init]; 
    }  
    // Fake loading an object by creating NSData of the given size 
    - (id) loadObjectNamed: (NSString *) someKey 
    {
         if (!allocationSize) 
         // pick your allocation size    
         allocationSize = 1024 * 1024;
         char *foo = malloc(allocationSize);
         NSData *data = [NSData dataWithBytes:foo length:allocationSize];
         free(foo);
         return data; 
    }  
    // When an object is not found, it's loaded 
    - (id) retrieveObjectNamed: (NSString *) someKey 
    {
         if (!myCache)
             self.myCache = [NSMutableDictionary dictionary];
         id object = [myCache objectForKey:someKey];
         if (!object)
         {
             if ((object = [self loadObjectNamed:someKey]))
                 [myCache setObject:object forKey:someKey];
         }     return object; 
    }  
    // Clear the cache at a memory warning 
    - (void) respondToMemoryWarning 
    {
         [myCache removeAllObjects]; 
    } 
    @end

    获取本配方代码 - 要获取本配方使用的代码,请访问 https://github.com/erica/iOS-5-Cookbook,或者如果您已下载包含本书所有示例代码的磁盘映像,请转到第 3 章的文件夹并打开本配方的项目。

    分析您的代码

    LLVM/Clang 静态分析器自动帮助检测 Objective-C 程序中的错误。它是一个出色的工具,用于查找内存泄漏和其他问题,尤其是 Core Foundation 和 MRR 代码。在 Xcode 中,选择“Product > Analyze”(Command-Control-B)。图 3-15 中显示的问题标记会引导您查看所有可疑泄漏和其他潜在问题。使用“Issue Navigator”窗格深入研究每个问题,并逐步了解导致分析器发出警告的逻辑。

    图 3-15
    Clang 静态分析器会为源代码创建错误报告,并将其嵌入到您的 Xcode 编辑器窗口中。Clang 对 MRR(如图所示)和 ARC 都很有用,并提供针对每种编译样式特有的报告。

    静态分析器发现的问题不一定是 bug。编写 Clang 识别为不正确的有效代码是可能的。在对代码进行任何更改之前,务必批判性地评估所有报告的问题。

    从 Xcode 到设备:Organizer 界面

    选择“Window > Organizer”(Command-Shift-2)以打开 图 3-16 所示的 Xcode Organizer 窗口。此窗口构成了开发计算机与 iOS 测试平台之间访问的控制中心。它允许您管理您的凭据、添加和删除应用程序、检查崩溃日志以及在测试应用程序时截取设备的屏幕截图。

    图 3-16
    Xcode 的 Organizer 窗口提供了一个中心枢纽,用于管理您的设备、证书和配置文件。

    Organizer 由两个主要部分组成:Library(资料库)和 Devices(设备),它们具有重叠的功能。资料库提供了基本上是设备日志、配置文件和屏幕截图的合并收件箱。这些在 Devices 部分中按设备分开列出。

    此外,资料库还有一个 Developer Profile 部分用于组织您的开发者证书,以及一个 Software Images 部分用于管理固件包。Devices 列表增加了每个设备的控制台和每个设备的应用程序管理。

    设备

    “设备”列表显示了您已授权为开发平台的设备的名称和状态。每个名称右侧的指示器显示设备是否已连接(绿灯)或未连接(白灯)。设备名称右侧的空白表示尚未设置为开发或已被“忽略”(即从活动列表中删除)的设备。当设备刚刚连接时,会出现琥珀色灯。如果灯仍然是琥珀色,您可能遇到了连接问题。这可能是由于 iTunes 同步,设备尚未可用,或者连接车载服务时可能存在问题,在这种情况下,重启 iOS 设备通常可以解决任何未解决的问题。

    每个设备的左侧都会出现一个展开按钮,提供对该设备特定信息的访问。您在这里找到的项目与 Organizer 的 Library 部分中列出的许多项目相同,包括设备日志、屏幕截图和配置文件。此外,您还可以访问设备控制台和应用程序列表。

    摘要

    选择设备名称会显示该设备的概览,包括设备的容量、序列号和标识符。您也可以在这里将最新固件加载到设备上。从软件弹出窗口中选择一个固件版本,然后点击“恢复”。此屏幕上的其他项目包括当前配置、应用程序、设备日志和屏幕截图的概览。

    请注意。当您升级到较新(尤其是测试版)的 iOS 版本时,设备降级并非总是可能。即使您已将旧固件存储在本地计算机上,降级也必须经过 Apple 签名服务器的授权。这些服务器允许 Apple 控制允许和不允许安装哪些旧固件,本质上为它们提供了一个滚动固件召回系统,随着时间的推移禁用旧固件。

    配置文件

    每个开发者许可证都允许您为测试配置您的个人或公司 iOS 设备。“配置”列表显示了可供您的设备使用的应用程序配置列表。您可以从此屏幕添加或删除配置。

    配置决定了哪些应用程序可以在设备上运行,哪些不能。通常,此处仅列出开发和 Ad Hoc 分发配置,这是有道理的。分发配置用于为 App Store 签署应用程序,而不是用于任何特定设备。

    设备日志

    通过从此屏幕的滚动列表中选择特定的崩溃(标有应用程序名称以及崩溃的日期和时间),可以直接访问您的崩溃日志。崩溃详细信息,包括堆栈跟踪、线程信息、异常类型等,将显示在右侧窗格中。您可以使用此屏幕上的按钮导入和导出日志。

    除了您自己生成的崩溃日志之外,您还可以从用户的家用计算机和 iTunes Connect 检索崩溃报告。当设备备份到 iTunes 时,iPhone 会自动将崩溃报告同步到计算机。这些报告存储在不同的位置,具体取决于用于同步设备的平台

    • Mac OS X—/Users/UserName/Library/Logs/CrashReporter/MobileDevice/ DeviceName
    • Windows XP—C:\Documents and Settings\UserName\Application Data\Apple Computer\Logs\CrashReporter\MobileDevice\DeviceName
    • Windows Vista—C:\Users\UserName\AppData\Roaming\Apple Computer\Logs\CrashReporter\MobileDevice\DeviceName

    iTunes Connect 从您的 App Store 用户那里收集崩溃日志数据并提供给您。通过选择“Manage Your Applications > App Details > View Crash Report”来下载任何应用程序的报告。您会在那里找到最常见的崩溃类型列表和每种类型的“Download Report”按钮。

    将报告复制到 Mac OS X 崩溃报告器文件夹中,它们会直接加载到 Organizer 中。请务必将它们加载到当前选定设备的设备文件夹中。报告会出现在 LIBRARY > Device Logs 中。

    一旦进入 Organizer,Xcode 会使用应用程序二进制文件和 .dSYM 文件,将报告通常提供的十六进制地址替换为函数和方法名称。这个过程称为“符号化”。您无需手动查找这些项目;只要原始二进制文件和 .dSYM 文件存在于您的主文件夹中的某个位置,Xcode 就会使用 Spotlight 和应用程序的唯一标识符 (UID) 来定位它们。Xcode 的归档功能提供了将这些材料保持在一起并持续可用的最佳方式。

    与 Organizer 中的崩溃日志一样,用户报告提供了一个堆栈跟踪,您可以将其加载到 Xcode 中以检测发生错误的位置。跟踪始终以倒序时间顺序出现,因此列表中的第一个项目是最后执行的项目。

    除了显示应用程序崩溃的位置外,崩溃报告还会告诉您崩溃的原因。最常见的原因是 EXC_BAD_ACCESS,这可能是由于访问未映射的内存 (KERN_INVALID_ADDRESS) 或尝试写入只读内存 (KERN_PROTECTION_FAILURE) 而生成的。

    崩溃报告中的其他重要项目包括崩溃的操作系统版本和崩溃的应用程序版本。用户并不总是将软件更新到最新版本,因此区分哪些崩溃是由于早期、现在可能已修复的版本引起的非常重要。

    注意 - 有关 iOS 崩溃报告的更多详细信息,请参阅 Apple 技术说明 TN2151。

    应用

    每台设备都提供了一个可浏览的已安装应用程序列表。使用“–”按钮删除选定的应用程序。要安装应用程序,请将其拖到列表中,或使用“+”按钮浏览查找。确保您的应用程序已为 iOS 编译,并且设备已配置为运行该应用程序。如果您自行签署应用程序并将其安装到设备上(本章稍后描述了操作过程),您的应用程序将使用您的团队配置文件。添加后,应用程序会立即同步到设备。从 App Store 安装的应用程序不再出现在应用程序列表中,这与 Xcode 3 中不同。

    要下载与应用程序相关联的数据,请点击其名称右侧的“下载”按钮。选择一个目标,然后点击“保存”。Xcode 会构建一个归档包,并用沙盒的内容填充它——即 Documents、Library 和 tmp 目录。Xcode 还会将文件夹添加到 Projects 和 Sources 列表中,您可以在 Organizer 中直接浏览其内容。

    您可以反转此过程,并将编辑后的沙盒添加回设备。找到您创建的捆绑包。将新项目放入任何封闭的子文件夹中,然后将整个文件夹拖回到“摘要”窗格底部的应用程序名称上。Xcode 会读取新项目并立即将其传输到设备。这是使用测试材料预填充沙盒的好方法。

    控制台

    使用控制台查看连接设备的系统消息。此屏幕显示 NSLog() 调用和发送到 stderr(标准错误输出)的其他消息,当您在连接的 iPhone 上运行软件时。您无需使用 Xcode 的调试器来执行此操作。控制台会监听设备上当前运行的任何应用程序。

    除了您添加到 iPhone 应用程序的调试消息外,您还会看到系统通知、设备信息以及 Apple 系统软件的调试调用。它基本上可以看作是一团基于文本的混乱,但您可以从中获取很多有价值的信息。点击“Save Log As”将控制台内容写入磁盘,或点击“Clear”清空控制台积压。

    屏幕截图

    通过点击“Screenshot”显示屏上的“New Screenshot”按钮,截取您连接的 iPhone 的屏幕。屏幕截图功能会拍摄 iPhone 上正在运行的任何内容的图片,无论您的应用程序是否打开。因此,您可以访问 Apple 内置软件和 iPhone 上运行的任何其他应用程序的截图。

    截图后,图像可以拖到桌面或保存为开放项目的新 Default.png 图像(“Save as Launch Image”)。存档的截图会出现在窗口左侧的资料库中。要删除截图,请选择一个并按 Delete 键永久删除。此屏幕上的其他功能允许您导出图像并比较图像以突出显示不同截图之间的差异。

    注意 - 屏幕截图存储在您的主目录 Library/Application Support/Developer/Shared/Xcode/Screenshots 文件夹中。

    为 iOS 设备构建

    在模拟器中构建和测试只能进行到此。iOS 开发的最终目标是创建在实际设备上运行的应用程序。有三种方法可以做到:为开发构建、为 App Store 分发构建和为 Ad Hoc 部署构建。这三种方法分别允许您在设备上进行本地测试、为 App Store 构建以及构建可在最多 100 台注册设备上运行的应用程序测试和审查版本。第 1 章介绍了移动配置并展示了如何在 Apple iOS Developer Program 门户中创建这些配置。现在是时候将这些付诸实践并将程序部署到设备本身了。

    使用开发配置文件

    开发配置文件是 iOS 部署的先决条件。您的团队配置文件由 Xcode 自动创建和管理。如果需要,您也可以在 Apple 的配置文件门户创建自己的通配符开发配置文件,但现在 Xcode 引入了团队配置文件,基本开发不再需要了。

    Xcode Organizer(Command-Shift-2)提供了管理您的配置文件、证书和设备的中心枢纽。图 3-16 显示了 Organizer 窗口,其中显示了“配置文件”组织器。

    要启用自动设备配置,请选中 图 3-16 底部所示的“Automatic Device Provisioning”复选框。此选项允许您直接从 Organizer 将新设备注册到 Apple。Xcode 会自动将设备信息上传到开发者门户并下载一个更新的配置,其中添加了新设备。

    当您需要直接向 Xcode 添加配置时,请点击窗口底部的“Import”按钮。导航到配置,选择它,然后点击“Open”。“配置文件”组织器还允许您查看配置创建和过期日期。

    “开发者配置文件”组织器列出了您所有用于开发和分发的 iOS 和 Mac 开发者证书。此组织器底部的“导入”和“导出”按钮允许您将您的开发者身份打包,以便轻松安全地传输到其他计算机。这些证书存储在您的系统钥匙串中。您可能需要查看您的钥匙串并确保 WWDR(全球开发者关系)证书可用。它不会直接列在“开发者配置文件”组织器中。

    在编译期间,Xcode 会将当前选定的配置与您的钥匙串身份进行匹配。这些必须匹配,否则 Xcode 将无法完成应用程序的编译和签名。要检查您的证书,请打开“钥匙串访问”(从 /Applications/Utilities),然后在右上角的搜索框中输入 developer。您至少应该看到您的 Apple Worldwide Developer Relations 认证机构和一个标有“iPhone Developer”后跟您的(公司)名称的证书。

    启用设备

    将您希望测试的设备连接到您的计算机。您可能需要先等待它在 iTunes 中完成同步。对于严肃的开发,您可以在 iTunes 中打开“偏好设置”(Command-,),选择“设备”选项卡,然后勾选“阻止 iPod、iPhone 和 iPad 自动同步”。点击“确定”以应用您的新设置。

    您可以直接从 Xcode 将设备添加到您的帐户。在 Xcode Organizer 中选择一个设备(“Window > Organizer”或 Command-Shift-2)。右键单击(或 Control-单击)其名称,然后选择“Add Device to Provisioning Portal”(参见 图 3-17)。

    图 3-17  
    使用设备组织器将设备添加到 iOS 配置文件门户。

    Xcode 会提示您使用您的程序凭据登录 iPhone 配置文件门户。一旦通过身份验证,它将上传设备详细信息并生成(或重新生成)您的团队配置文件。

    首次开发者有时会担心他们的设备会被锁定在某种“开发模式”中,这主要是由于 Apple 的标准警告文本;实际上,我从未听说过任何长期问题。无论如何,在将您的设备用作开发设备之前,请做好功课。阅读最新的 SDK 发布说明以获取详细信息。

    检查您的应用程序标识符

    您的项目应用程序标识符可以根据需要进行检查和更新。在 Project Navigator 中选择项目,然后选择 TARGETS > Project Name。选择“Info”选项卡以显示“Custom iOS Target Properties”,如 图 3-18 所示。可以通过编辑“Bundle Identifier”字段手动设置应用程序标识符。Xcode 默认使用您的 RFC 1034 反向域名根标识后跟产品名称。

    图 3-18
    “信息”选项卡允许您编辑“Bundle”标识符。

    您的团队开发配置会自动匹配所有项目;其注册标识符是一个通配符星号 (*)。其他配置可能匹配也可能不匹配您正在使用的应用程序标识符。例如,如果您注册了一个通配符应用程序标识符,比如 com.sadun.*,并用它来生成配置文件,那么它会匹配 com.sadun.helloworld 或 com.sadun.testing,但不会匹配 helloworld 或 com.mycompany.helloworld。

    设置您的设备和代码签名身份

    检查完您的标识符后,点击 PROJECT > 项目名称 > Build Settings。在 Build Settings 窗格右上角的搜索字段中输入 device。这应该匹配一个设置:Targeted Device Family。使用此弹出菜单选择您希望编译的设备:iPhone、iPad 或 iPhone/iPad。最后一个选项允许您构建一个通用应用程序,该应用程序可以安装并在两种设备上运行,利用每个系统的原生几何图形。

    接下来,确认您的代码签名身份。确保您正在查看所有设置(而不仅仅是基本设置)。在右上角的搜索字段中输入 signing。从每个构建类型右侧出现的弹出列表中选择您的身份。随着您开始累积配置和身份,选项列表可能会变得很长,特别是如果您参与第三方测试的话。

    两个自动配置文件选择器会自动选择第一个匹配的配置文件。我足够偏执,在选择配置文件之前总是会检查证书名称和该名称上方的配置文件身份。Apple 建议使用自动选择。

    设置您的基本和部署 SDK 目标

    “基本 SDK 目标”设置指定用于编译应用程序的 SDK 版本。打开“PROJECT > 项目名称 > Build Settings”,并在列表顶部找到“Base SDK”。通常,您可以将此选项设置为“Latest iOS”。它会自动匹配最新安装的 SDK。这意味着如果您的代码使用了最新引入的 API,它将不会编译失败。编译器会正确处理这些问题。但是,如果在新固件版本不支持的设备上调用新的 API(例如,在 4.3 设备上调用 5.1 API),您的代码在执行时仍可能失败。这不是您通过“Base SDK”解决的问题,而是通过部署目标解决的问题(参见 图 3-19)。

    图 3-19
    基本 SDK 设置用于编译应用程序的 iOS 版本。armv7 架构目前可在 iPhone 3GS 及更新机型、iPod touch 3G 及更新机型以及所有 iPad 上使用。

    在“摘要”视图的第一部分中,将部署目标设置为“TARGET > project name > Summary > iOS Application Target”。此弹出菜单(参见 图 3-20)指定您希望允许应用程序安装到的最早设备。

    图 3-20
    部署目标设置允许运行您的应用程序的最早 iOS 版本。

    如果您在 5.x 中编译并部署到 4.x,您可以在代码中使用 5.x 调用,但您需要使用运行时检查来确保您不会在不支持它们的平台上调用 API,并对部署目标上找不到的任何框架进行弱链接。运行时和编译时代码检查都将在本章后面介绍。将部署目标设置为基本 SDK 目标可确保您无需进行任何运行时 API 检查,但将您的受众限制为仅那些已将其设备更新到最新固件的客户。您支持的早期固件版本越多,尤其是在同一 iOS 发布系列中(例如 4.x、5.x 等),您的潜在用户群就越大。

    编译并运行 Hello World 应用程序

    最后,是时候在真实的 iPhone、iPod touch 或 iPad 上测试 Hello World 了。在编译之前,您必须告诉 Xcode 为 iOS 设备的 ARM 架构而不是模拟器的 Intel 架构构建。找到工作区工具栏左上角的方案弹出菜单并打开它。它应该看起来像 图 3-21。设备名称出现在列表顶部,模拟器选项出现在底部。Xcode 会突出显示固件与部署目标匹配但早于基本 SDK 的设备。选择一个设备。

    图 3-21
    Xcode 特别强调了固件落后于基本 SDK 的设备。旧版固件安装构成测试基础的关键组成部分,有助于确保您的代码在所有有效部署目标上都能正常工作。

    选择“Product > Run”(Command-R)或点击工作区工具栏左侧的“运行”按钮(它看起来像一个播放按钮)。假设您已正确遵循本章前面的说明,Hello World 项目应该会编译无误,复制到 iPhone 并开始运行。

    如果项目警告您没有连接配置的设备,请打开 Xcode Organizer 窗口并验证设备旁边的点是否为绿色。如果不是这种情况,您可能需要重启 Xcode 或重启您的设备或计算机。

    签署已编译的应用程序

    您可以使用简单的 shell 脚本在命令行上签署已编译的应用程序。这适用于为开发构建的应用程序。直接签署应用程序有助于开发者在 Ad Hoc 渠道之外共享应用程序。

    #! /bin/bash  export CODESIGN_ALLOCATE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/ bin/codesign_allocate  codesign -f -s "iPhone Developer" $1.app

    如果您在钥匙串中使用了多个 iPhone 开发者配置文件,您可能需要调整此脚本,使其只匹配其中一个;否则,codesign 会抱怨匹配不明确。

    我个人使用这种方法分发本书示例代码的测试版本。使用开发者代码签名可以省去 Ad Hoc 分发的麻烦,允许快速测试周转,而不会占用宝贵的设备槽位。

    使用编译时检查检测模拟器构建

    Xcode 指令会向编译器发出指示,以检测您正在构建的平台。这使您可以自定义应用程序,以便在可用时安全地利用仅限设备的功能。在代码中添加 #if 语句可让您根据这些选项阻止或显示功能。要检测您的代码是为模拟器还是为 iOS 设备编译的,请使用编译时检查

    #if TARGET_IPHONE_SIMULATOR     Code specific to simulator #else     Code specific to iPhone #endif

    执行运行时兼容性检查

    iOS 设备用户之间存在真实且可衡量的采用滞后。为了将您的应用程序销售给最多的客户,不要构建高于您最低所需客户的任何 SDK。在选择该 SDK 时请运用常识。您可能会发现最好支持落后于最新 iOS 更新几周或几个月的最新固件点发布版本,或者您可能希望将支持扩展到当前 iOS 固件的所有版本。

    当 iOS 升级到新版本时,最困难的决定就会出现。那时采用率下降最多。3.x/4.x 的重叠持续了一段时间,然后开发者才自信地转向仅 4.x 版本。iOS 5 及其后续版本继续面临这一挑战。

    要构建针对一系列可能的部署目标,请将您的 Base SDK 设置为您要定位的 OS 的最高版本(通常是当前的 SDK 版本)。将您的 iOS 部署目标设置为您打算构建的最低 OS 版本。

    当编译到早于您的基本 SDK 的部署目标时,您需要对可能尚未引入给定固件平台的任何类或 API 调用执行运行时检查。例如,iOS 5 引入的 API 调用在 iOS 4.2 安装上将不可用。以下测试允许您在运行时检查可能可用或不可用的类和方法,具体取决于部署平台

    • 检查平台几何形状——iOS 3.2 中引入的 idiom 检查可让您确定代码是在 iPhone 类似设备(iPhone、iPod touch)还是 iPad 上运行。我在此处没有包含扩展来查看检查本身是否已实现,仅仅是因为我不再推荐部署到 3.2 之前的平台。截至 2011 年夏季,3.x 平台仅占所有 iOS 安装的大约 5%。3.2 之前的安装仅占其中的极小一部分。
    • if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) . . .
    • 检查部署平台——使用 UIDevice 类的 model 属性来确定设备是否在 @"iPhone" 上运行,如果 ([[UIDevice currentDevice].model isEqualToString:@"iPad"]) . . .
    • 检查系统前缀——这不是最好的编码方法(直接检查类和实例要可靠得多),但您_可以_直接检查当前系统版本。
    • if ([[[UIDevice currentDevice] systemVersion] hasPrefix:@"5."])  . . .
    • 使用键值编码检查属性——您可以确定对象是否在当前作用域内为给定键提供了值,这允许您测试属性。
    • UILabel *label = (UILabel *)[cell valueForKey:@"textLabel"]; if (label) [label setText:celltext];
    • 检查类是否存在——如果某个类在给定部署目标上可能不存在,请使用 NSClassFromString() 测试是否可以从其名称生成该类。将它传递给 NSString,例如以下内容
    • if (NSClassFromString(@"NSAttributedString")) . . .
    • 检查函数是否存在——您可以在尝试调用函数之前测试它们是否存在。
    • if(&UIGraphicsBeginImageContextWithOptions != NULL) . . .
    • 检查选择器兼容性——您可以测试对象是否响应特定的选择器。当支持较新的 API 时,对象将报告它们响应这些选择器,让您可以在不使程序崩溃的情况下调用它们。除非您使用诸如 performSelector:withObject: 等变通方法,否则您可能会生成有关未实现选择器的编译时警告。如果您真的想深入研究,可以直接构建 NSInvocation 实例,如第 3 章所述。
    if ([cell respondsToSelector:)]) . . .

    Pragma 标记

    Pragma 标记通过在每个 Xcode 窗口顶部的方法列表弹出按钮中添加书签来组织您的源代码。此列表显示当前文档中可用的所有方法和函数。添加 pragma 标记允许您将相关项分组在一起,如 图 3-22 所示。通过从下拉列表中点击这些标签,您可以跳转到文件的一个部分(例如,到 UtilityRAOP)以及一个特定的方法(例如 -hexStringFromBytes:)。

    图 3-22
    使用 pragma 标记组织您的方法和函数列表。

    要创建新书签,请在代码中添加 pragma 标记定义。例如,要复制 图 3-22 中的第一个组,请添加以下内容

    #pragma mark Class

    您还可以使用单个破折号添加分隔线。这使用快捷方式添加分隔符和标记

    #pragma mark –

    #pragma mark – Marker Title

    这些标记没有功能,也不会影响您的代码。它们只是您选择使用或不使用的组织工具。

    折叠方法

    当您需要同时查看代码的多个部分时,Xcode 允许您关闭和打开方法组。将鼠标放在任何方法左侧的槽位中。会出现一对展开三角形。点击一个三角形,Xcode 会折叠该方法的代码,如 图 3-23 所示。省略号表示折叠的方法。点击展开三角形,Xcode 会显示折叠的代码。您还可以折叠任何复合语句。

    图 3-23
    Xcode 允许您折叠单个方法和函数。这使您可以看到程序中通常无法同时显示在屏幕上的部分。

    准备分发

    为分发构建意味着创建应用程序的版本,该版本可以提交给 Apple 在 App Store 中销售。在开始提交之前,了解如何清理构建、如何编辑和使用方案以及如何创建应用程序的存档。您需要精确地为 App Store 编译。先清理,然后为分发编译有助于确保您的应用程序正确上传。归档会生成一个可以共享和提交的应用程序捆绑包。本节涵盖了这些技能以及分发编译中使用的其他技能。

    定位和清理构建

    Xcode 4 采用了一种新的方法来构建代码和存储构建产品。在 Xcode 3 中,编译后的代码被添加到项目文件夹中的“build”子文件夹中。在 Xcode 4 中,应用程序默认在您的主目录中创建,位于 ~/Library/Developer/Xcode/DerivedData。您可以通过在 Project Navigator 的 Products 组中选择构建产品来定位它。右键单击应用程序并选择“Show in Finder”。用于构建共享给他人或提交到 App Store 的产品的项目存档存储在 ~/Library/Developer/Xcode/ Archives 中。

    清理您的构建会强制项目的每个部分从头开始重新编译。执行清理操作还可以确保您的项目构建包含项目资产(包括图像和声音)的当前版本。您可以通过选择“Product > Clean”(Command-Shift-K)来强制执行清理。

    Apple 建议在编译任何应用程序以供 App Store 审核之前进行清理,这是一个好习惯。

    使用方案和操作

    在 Xcode 中,方案存储项目构建设置。它们指定要构建的目标、要应用的配置选项以及可执行环境将如何设置。操作是您可以执行的单独任务,用于创建构建以及测试、分析、分析和存档您的应用程序。

    每个方案由一个项目和一个目标组成。图 3-24 显示了本章中 Hello World 项目的方案弹出菜单。通过选择“运行”按钮右侧的“Hello World”来访问此弹出菜单。这是一种有趣的弹出菜单,因为它实际上是分开的。点击嵌入式 V 形符号的左侧或右侧会提供两个略有不同的菜单。

    图 3-24
    方案弹出菜单包含方案及其运行目标,后跟管理选项。

    点击左侧会显示 图 3-24 中所示的弹出菜单。此弹出菜单包括方案列表(此处只有一个)及其可能的运行目标。此处,目标包括设备和四种模拟器样式(适用于 iOS 4.3 和 iOS 5.0 的 iPhone 和 iPad)。方案列表之后是菜单行,后跟三个用于编辑、创建和管理方案的选项。

    点击右侧仅显示目标子菜单,允许您为当前方案选择目标。目标包括任何已配置且已启用开发的 iOS 设备,以及部署构建设置的所有可能模拟器选项。

    注意 - 在 Xcode 中,scheme 的复数是 schemes,而不是 schema 或 schemata。正如 iOS 开发者 Nate True 所说,“在 Xcode 中,它是 schemata non grata。”

    选择您的方案后,从弹出菜单中选择“Edit Scheme”以查看可用操作列表。图 3-24 显示了与 Hello World 方案关联的操作。每个操作代表一个单独的开发任务。它们包括以下内容

    • 构建——构建代码
    • 运行——在设备或模拟器中运行编译后的代码
    • 测试——使用 Xcode 单元测试工具来压力测试应用程序功能
    • 分析——使用 Instruments 进行实时采样运行代码
    • 静态分析——将静态分析器应用于未解决的问题
    • 归档——准备应用程序以共享或提交到 App Store

    使用此方案编辑器自定义每个操作在 Xcode 中的工作方式。例如,在 图 3-25 中所示的“Run”操作中,调试器设置为 LLDB。您可以轻松地从弹出菜单中选择 GDB 来更改它。

    图 3-25
    方案的操作列表提供了一组在应用程序创建过程中可能需要执行的任务。

    您已经在前面本章的 Instruments 演练中看到了操作菜单。通过点击并按住 Xcode 窗口左上角的“运行”菜单来访问它。从弹出菜单中选择您要执行的操作。“运行”按钮会更新以显示新的操作项。

    添加构建配置

    构建配置允许您指定应用程序应如何构建。它们充当您希望一切设置就绪的快速参考,因此您只需选择一个配置即可为您的设备或 App Store 进行编译。它们对于添加插装和条件编译也很有用。标准的 Xcode 项目提供 Debug 和 Release 配置。您可能希望创建一些其他配置,例如用于 Ad Hoc 分发的配置。

    配置是在 PROJECT > 项目名称 > Info 屏幕的 Configurations 部分创建和管理的(参见 图 3-26)。假设您一直在跟着本章进行操作,您已经设置了 HelloWorld 项目并编辑了其调试构建设置。它使用您的团队通配符配置来签署应用程序。与其每次想要切换签署配置时都编辑构建设置,不如创建一个新配置。典型的配置选项包括您希望构建的架构和您的默认代码签名身份。

    图 3-26
    使用“信息”>“配置”窗格创建新配置,以便您可以使用预设选项(如签名身份)进行构建。

    在以下部分中,您将阅读有关向您的项目添加 Ad Hoc 配置的信息。这实际上仅用于示例目的——因为我真的想不出很多您会想要更改 Ad Hoc 与 App Store 的构建设置的方式,而且您可以在 Organizer 中为这两个目标创建捆绑包时选择您的签名身份。请根据您的实际需求调整此示例及其步骤。

    注意 - 您可以通过使用不同的捆绑包 ID、产品名称或添加额外的警报来区分您的 Ad Hoc 配置构建,以便更轻松地与 App Store 版本一起运行。使用 #ifdef 指令来区分 Ad Hoc 代码更改。

    关于 Ad Hoc 分发

    Apple 允许您通过 Ad Hoc 分发在 App Store 之外分发您的应用程序。通过 Ad Hoc,您可以将您的应用程序发送到最多 100 台注册设备,并使用一种特殊类型的移动配置文件运行这些应用程序,该配置文件允许应用程序在 iPhone 的 FairPlay 限制下执行。Ad Hoc 分发对于 Beta 测试以及向新闻网站和杂志提交审查应用程序特别有用。

    Ad Hoc 流程从注册设备开始。使用 iPhone 开发者计划门户将设备标识符(Program Portal,Devices)和名称添加到您的帐户。您可以直接从 iPhone(使用 UIDevice 类)、从 Xcode 的 Organizer(从概览选项卡复制标识符)、从 iTunes(点击 iPhone“摘要”选项卡中的“序列号”)或通过 iTunes 上提供的免费 Ad Hoc Helper 应用程序检索这些标识符。输入标识符和唯一的用户名。

    要创建新的 Ad Hoc 配置,请在 iOS 门户创建新的配置。选择“Program Portal > Provisioning > Distribution”。点击“Add Profile”。选择“Ad Hoc”,输入配置文件名称、您的标准通配符应用程序标识符(例如,com.yourname.*),然后选择要部署的设备。别忘了检查您的身份,然后点击“Submit”并等待 Apple 构建新的移动配置文件。下载配置文件并将其拖到 Xcode 应用程序图标上。

    有了新的配置文件后,复制“Release”配置。Xcode 会创建一个副本并打开一个文本输入字段供其命名。将名称从“Release copy”编辑为“Ad Hoc”。

    接下来,点击“Build Settings”选项卡并找到“Code Signing”部分。将您的新 Ad Hoc 配置分配给您的 Ad Hoc 配置。使用“Any iOS SDK”右侧的弹出菜单。然后选定的配置会出现在“Code Signing Identity”列表中,如 图 3-27 所示。

    图 3-27
    新配置会单独出现在构建设置的“代码签名”部分。

    最后,在“Scheme editor”的“Archive action”部分中选择您的新构建配置。

    注意 - 除了手动添加新配置外,您还可以使用包含文本格式设置定义的构建配置文件。通过选择“文件”>“新建”>“新建文件”>“其他”>“配置设置”来创建这些文件。您可以在 Apple 的 Xcode 构建系统指南中阅读更多关于创建配置文件的信息。

    构建 Ad-Hoc 包

    1. 当您准备好与 Ad Hoc 列表中的成员共享您的应用程序时,请遵循以下步骤:
    2. 如果您希望使用自定义编译器方案,请从 Xcode 窗口顶部的方案弹出菜单中选择“Edit Scheme”。选择“Archive”并根据需要设置您的“Build Configuration”。点击“OK”。如果您希望使用默认编译器方案,可以跳过此步骤。
    3. 从 Xcode 主菜单中选择“Product > Archive”。
    4. 等待 Xcode 完成工作。完成后,Organizer 将打开,显示“Archives”选项卡。此屏幕允许您查看、管理和使用应用程序的存档副本。您还可以为每个存档添加自由格式的评论——这是一个非常方便的功能——并且状态行允许您跟踪存档何时成功提交到 App Store。
    5. 对于 Ad Hoc 分发,请点击“Share”。选择“iOS App Store Package (.ipa)”作为您的目标。
    6. 从“Identity”弹出菜单中选择您的 Ad Hoc 配置文件,然后点击“Next”。
    7. 指定新包的名称(例如,HelloApp)以及保存位置。点击“保存”。

    完成这些步骤后,您现在可以将新构建的 .ipa 文件通过电子邮件发送给您的测试版列表成员,或将其发布到中央网站供下载。

    您构建的 .ipa 捆绑包实际上是一个重命名的 ZIP 文件。如果您将其解压并查看 Payload 文件夹内部,您会发现编译后的应用程序捆绑包。这包含一个嵌入的移动配置文件,其中列出了 Ad Hoc 配置中包含的所有设备 ID。

    <string>Wildcard Ad Hoc </string> <key>ProvisionedDevices</key>

    注意 - TestFlight 提供了无线 Ad Hoc 管理,这在开发者社区中变得非常流行。访问 testflightapp.com 获取详细信息。

    无线 Ad Hoc 分发

    您可以通过创建指向简单网页的链接来无线分发 Ad Hoc ipa 文件。当 itms-services: URL 方案指向应用程序清单属性列表时,您的用户可以无线安装应用程序。您在网站上提供 ipa 和清单。以下是您可能如何链接到清单的示例。

    <a href="itms-services://?action=download-manifest&\     url=http://example.com/manifest.plist">Install App</a>

    确保您的网站已配置为支持以下两种 MIME 类型。

    application/octet-stream ipa text/xml plist

    构建清单

    清单是一个基于 XML 的属性列表。它必须包含六个键/值对

    • URL——指向 ipa 文件的完整 URL
    • display-image——指向下载和安装期间使用的 57x57 像素 PNG 图标的完整 URL
    • full-size-image——指向代表 iTunes 应用程序的 512x512 像素 PNG(不是 JPEG!)图像的完整 URL
    • bundle-identifier——应用程序的标准应用程序标识符字符串,如应用程序的 Info.plist 文件中指定
    • bundle-version——应用程序的当前捆绑包版本字符串,如应用程序的 Info.plist 文件中指定
    • title——人类可读的应用程序名称

    除了这些必需的键之外,您还可以为文件元素指定可选的 md5 哈希值。清单 3-3 显示了 Apple 提供的示例清单。

    清单 3-3  Apple 示例清单

    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict>
        <!-- array of downloads. -->
        <key>items</key>
        <array>
            <dict>
                <!-- an array of assets to download -->
                <key>assets</key>
                <array>
                    <!-- software-package: the ipa to install. -->
                    <dict>
                        <!-- required.  the asset kind. -->
                        <key>kind</key>
                        <string>software-package</string>
                        <!-- optional.  md5 every n bytes.  -->
                        <!-- will restart a chunk if md5 fails. -->
                        <key>md5-size</key>
                        <integer>10485760</integer>
                        <!-- optional.  array of md5 hashes -->
                        <key>md5s</key>
                        <array>
                            <string>41fa64bb7a7cae5a46bfb45821ac8bba</string>
                            <string>51fa64bb7a7cae5a46bfb45821ac8bba</string>
                        </array>
                        <!-- required.  the URL of the file to download. -->
                        <key>url</key>
                        <string>http://www.example.com/apps/foo.ipa</string>
                    </dict>
                    <!-- display-image: the icon to display during download .-->
                    <dict>
                        <key>kind</key>
                        <string>display-image</string>
                        <!-- optional. icon needs shine effect applied. -->
                        <key>needs-shine</key>
                        <true/>
                        <key>url</key>
                        <string>http://www.example.com/image.57x57.png</string>
                    </dict>
                    <!-- full-size-image: the large 512x512 icon used by iTunes. -->
                    <dict>
                        <key>kind</key>
                        <string>full-size-image</string>
                        <!-- optional.  one md5 hash for the entire file. -->
                        <key>md5</key>
                        <string>61fa64bb7a7cae5a46bfb45821ac8bba</string>
                        <key>needs-shine</key>
                        <true/>
                        <key>url</key>
                        <string>http://www.example.com/image.512x512.jpg</string>
                    </dict>
                </array><key>metadata</key>
                <dict>
                    <!-- required -->
                    <key>bundle-identifier</key>
                    <string>com.example.fooapp</string>
                    <!-- optional (software only) -->
                    <key>bundle-version</key>
                    <string>1.0</string>
                    <!-- required.  the download kind. -->
                    <key>kind</key>
                    <string>software</string>
                    <!-- optional. displayed during download; -->
                    <!-- typically company name -->
                    <key>subtitle</key>
                     <string>Apple</string>
                     <!-- required.  the title to display during the download. -->
                     <key>title</key>
                     <string>Example Corporate App</string>
                 </dict>
             </dict>
         </array>
      </dict> 
    </plist>

    提交到 App Store

    为了使您的应用程序符合 App Store 的提交政策,它必须使用有效的开发者身份通过有效的发布配置文件进行签名。这些步骤与您用于创建 Ad Hoc 分发的步骤非常相似,但您必须执行额外的簿记工作。

    请确保您至少有一张 512·512 像素的 PNG 图片,以及至少一张截图,以备接下来的几个步骤使用。如果您尚未准备好最终的美术作品,可以上传占位符,并在需要时替换或删除它们。

    首先访问 iOS 门户并在门户的“App IDs”选项卡中注册您的应用程序标识符。这只需要一两秒钟,并且需要一个通用名称(例如,“Collage”)和标识符(例如,com.sadun.Collage)。此标识符应与您在 Xcode 中使用的标识符完全匹配。尽管您通常使用通用通配符配置文件签署您的应用程序,但您在 iTunes 中需要的应用程序标识符必须是特定的。

    前往 iTunes Connect (iTunesConnect.apple.com)。选择“Manage Your Applications > Add New App > iOS App”。输入应用程序名称(必须是唯一的)、SKU 号码(如何定义取决于您,但必须是您的帐户独有的),然后从“Bundle ID”弹出菜单中选择您的新标识符。在此屏幕上尽可能精确,并且在此步骤中不要使用占位符。务必确保选择正确的标识符。一旦设置,它就无法更改。

    输入所有元数据(此处都可以是占位符),并设置您的两张图片。iTunes Connect 会创建您的新应用程序页面并添加一个“Ready to Upload Binary”按钮。当您点击该按钮并声明您的导出加密合规性时,您将获得如何上传二进制文件的说明。您的应用程序状态从“Ready to Upload”变为“Waiting for Upload”。点击“Continue”。

    当您在 iPhone 元数据中使用占位符时,您现在有足够的时间编辑这些材料。请务必在从 Xcode 上传应用程序_之前_整理好您的描述和艺术作品。您的上传会启动 App Store 审核流程。在您的应用程序准备好审核之前,请勿上传它,以免浪费 Apple 应用程序审核人员的时间。

    最后,请务必阅读 Apple 的 App Store 提交指南,它会引导您完成整个流程及其准则,这些准则有助于解释哪些应用程序适合 App Store,哪些不适合。

    无线 Ad Hoc 分发

    您可以通过创建指向简单网页的链接来无线分发 Ad Hoc ipa 文件。当 itms-services: URL 方案指向应用程序清单属性列表时,您的用户可以无线安装应用程序。您在网站上提供 ipa 和清单。以下是您可能如何链接到清单的示例。

    <a href="itms-services://?action=download-manifest&\     url=http://example.com/manifest.plist">Install App</a>

    确保您的网站已配置为支持以下两种 MIME 类型。

    application/octet-stream ipa text/xml plist

    构建清单

    清单是一个基于 XML 的属性列表。它必须包含六个键/值对

    • URL——指向 ipa 文件的完整 URL
    • display-image——指向下载和安装期间使用的 57x57 像素 PNG 图标的完整 URL
    • full-size-image——指向代表 iTunes 应用程序的 512x512 像素 PNG(不是 JPEG!)图像的完整 URL
    • bundle-identifier——应用程序的标准应用程序标识符字符串,如应用程序的 Info.plist 文件中指定
    • bundle-version——应用程序的当前捆绑包版本字符串,如应用程序的 Info.plist 文件中指定
    • title——人类可读的应用程序名称

    除了这些必需的键之外,您还可以为文件元素指定可选的 md5 哈希值。清单 3-3 显示了 Apple 提供的示例清单。

    清单 3-3  Apple 示例清单

    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
     <plist version="1.0"> <dict>
         <!-- array of downloads. -->
         <key>items</key>
         <array>
             <dict>
                 <!-- an array of assets to download -->
                 <key>assets</key>
                 <array>
                     <!-- software-package: the ipa to install. -->
                     <dict>
                         <!-- required.  the asset kind. -->
                         <key>kind</key>
                         <string>software-package</string>
                         <!-- optional.  md5 every n bytes.  -->
                         <!-- will restart a chunk if md5 fails. -->
                         <key>md5-size</key>
                         <integer>10485760</integer>
                         <!-- optional.  array of md5 hashes -->
                         <key>md5s</key>
                         <array>
                             <string>41fa64bb7a7cae5a46bfb45821ac8bba</string>
                             <string>51fa64bb7a7cae5a46bfb45821ac8bba</string>
                         </array>
                         <!-- required.  the URL of the file to download. -->
                         <key>url</key>
                         <string>http://www.example.com/apps/foo.ipa</string>
                     </dict>
                     <!-- display-image: the icon to display during download .-->
                     <dict>
                         <key>kind</key>
                         <string>display-image</string>
                         <!-- optional. icon needs shine effect applied. -->
                         <key>needs-shine</key>
                         <true/>
                         <key>url</key>
                         <string>http://www.example.com/image.57x57.png</string>
                     </dict>
                     <!-- full-size-image: the large 512x512 icon used by iTunes. -->
                     <dict>
                         <key>kind</key>
                         <string>full-size-image</string>
                         <!-- optional.  one md5 hash for the entire file. -->
                         <key>md5</key>
                         <string>61fa64bb7a7cae5a46bfb45821ac8bba</string>
                         <key>needs-shine</key>
                         <true/>
                         <key>url</key>
                         <string>http://www.example.com/image.512x512.jpg</string>
                     </dict>
                 </array><key>metadata</key>
                 <dict>
                     <!-- required -->
                     <key>bundle-identifier</key>
                     <string>com.example.fooapp</string>
                     <!-- optional (software only) -->
                     <key>bundle-version</key>
                     <string>1.0</string>
                     <!-- required.  the download kind. -->
                     <key>kind</key>
                     <string>software</string>
                     <!-- optional. displayed during download; -->
                     <!-- typically company name -->
                     <key>subtitle</key>
                     <string>Apple</string>
                     <!-- required.  the title to display during the download. -->
                     <key>title</key>
                     <string>Example Corporate App</string>
                 </dict>
             </dict>
         </array>
      </dict> 
     </plist>

    提交到 App Store

    为了使您的应用程序符合 App Store 的提交政策,它必须使用有效的开发者身份通过有效的发布配置文件进行签名。这些步骤与您用于创建 Ad Hoc 分发的步骤非常相似,但您必须执行额外的簿记工作。

    请确保您至少有一张 512·512 像素的 PNG 图片,以及至少一张截图,以备接下来的几个步骤使用。如果您尚未准备好最终的美术作品,可以上传占位符,并在需要时替换或删除它们。

    首先访问 iOS 门户并在门户的“App IDs”选项卡中注册您的应用程序标识符。这只需要一两秒钟,并且需要一个通用名称(例如,“Collage”)和标识符(例如,com.sadun.Collage)。此标识符应与您在 Xcode 中使用的标识符完全匹配。尽管您通常使用通用通配符配置文件签署您的应用程序,但您在 iTunes 中需要的应用程序标识符必须是特定的。

    前往 iTunes Connect (iTunesConnect.apple.com)。选择“Manage Your Applications > Add New App > iOS App”。输入应用程序名称(必须是唯一的)、SKU 号码(如何定义取决于您,但必须是您的帐户独有的),然后从“Bundle ID”弹出菜单中选择您的新标识符。在此屏幕上尽可能精确,并且在此步骤中不要使用占位符。务必确保选择正确的标识符。一旦设置,它就无法更改。

    输入所有元数据(此处都可以是占位符),并设置您的两张图片。iTunes Connect 会创建您的新应用程序页面并添加一个“Ready to Upload Binary”按钮。当您点击该按钮并声明您的导出加密合规性时,您将获得如何上传二进制文件的说明。您的应用程序状态从“Ready to Upload”变为“Waiting for Upload”。点击“Continue”。

    当您在 iPhone 元数据中使用占位符时,您现在有足够的时间编辑这些材料。请务必在从 Xcode 上传应用程序_之前_整理好您的描述和艺术作品。您的上传会启动 App Store 审核流程。在您的应用程序准备好审核之前,请勿上传它,以免浪费 Apple 应用程序审核人员的时间。

    最后,请务必阅读 Apple 的 App Store 提交指南,它会引导您完成整个流程及其准则,这些准则有助于解释哪些应用程序适合 App Store,哪些不适合。

    注意 - 特别注意“应用程序元数据”中的“审核备注”区域。这是您与 Apple 审核人员进行人工沟通的唯一途径。使用此部分解释您认为审核人员可能遇到的任何困惑之处。如有需要,提供操作步骤和用于测试应用程序的示例帐户凭据。

    当您完全确定已准备好提交应用程序时,请按照以下步骤操作

    1. 审查您的 iTunes Connect 元数据,确保清晰准确。
    2. 归档您的应用程序(Product > Archive)。
    3. 在 Organizer 中,点击“Submit”。
    4. 输入您的开发者登录凭据,然后点击“Next”。
    5. 从顶部弹出菜单中选择您的应用程序(参见 图 3-28)。此列表中仅显示“Waiting for Upload”的应用程序。
    6. 从底部弹出菜单中选择您的分发身份。确保它是您的通用分发身份,而不是 Ad Hoc 分发身份!这是一个常见错误,通常会导致 iTunes 发送电子邮件要求您在代码签名检查失败后重新提交应用程序。点击“Next”。
    7. 等待 Xcode 验证并提交您的应用程序。完成后,应用程序名称旁边的“Status”字段会更新,以匹配您的提交状态。等待 iTunes 发送电子邮件,告知您的应用程序状态已更改为“Waiting for Review”。
    图 3-28
    只有“等待上传”的应用程序才会列在 Organizer 的提交屏幕中。请确保您的身份未设置为 Ad Hoc 配置文件,也列为 iPhone Distribution。这是许多开发者常犯的错误。

    如果您在上传过程中遇到任何问题,您可能需要清理项目并从头开始重新编译。如果您无法验证或提交您的应用程序,请尝试重新安装 Xcode。有时,当您在与主要开发 Xcode SDK 相同的机器上安装 SDK 的测试版时,这些版本可能会覆盖您正确提交应用程序到 iTunes Connect 所需的工具。

    注意 - 密切关注您的日历。您必须每年续订您的开发者会员资格。您的证书也都有有效期。在续订您的开发者和分发证书时,您必须重新颁发所有移动配置文件。丢弃旧的,并使用您更新的开发者身份创建新的。在用新证书替换过时的证书时,请务必从钥匙串中删除它们。

    摘要

    本章涵盖了很多内容。从头到尾,您看到了如何创建、编译和调试 Xcode 项目。您接触了日常使用的大多数主要 Xcode 组件,并且阅读了许多不同方式来生成和运行 iPhone 项目。以下是本章的一些思考

    • 虽然 Xcode 提供了易于使用的模板,但请将其视为一个起点,而不是终点。您可以根据需要自定义和编辑项目。
    • Interface Builder 使布局视图变得非常容易。尽管从技术上讲,您正在生成与手动设计时相同的方法调用和属性赋值,但 IB 优雅的 GUI 将这些设计任务转换为视觉领域,这对许多开发者来说是一个受欢迎的地方。
    • 学习如何通过 Xcode 的程序内参考文档进行导航是成为 iPhone 开发者不可或缺的一部分。没有人能将所有这些信息都记在脑海中。您越精通文档界面,就越能找到您需要前进的类、方法或属性。
    • 一切都在变化。订阅 Xcode 中的 iOS 文档,并确保您的文档尽可能保持最新。
    • Xcode 内置的调试器和 Instruments 工具可以帮助您比手动解决所有问题更快地修复错误。这些工具乍一看可能很复杂,但对于日常开发来说,它们非常值得掌握。
    • 了解并喜欢 Organizer 窗格。它为您提供了关键反馈,让您了解哪些设备已连接以及它们处于什么状态。而其他工具——包括提交到 App Store 的项目存档、文档界面和屏幕截图实用程序——只会增加它的强大功能。
    • Xcode 4 的重大更新拥有比本简要介绍所能涵盖的更多功能和能力。其他功能将在第 4 章“设计界面”中讨论,该章提供了 Interface Builder 的更详细概述。

    © Pearson Education 版权所有。保留所有权利。

    iOS 5 开发者食谱:构建您的第一个项目 - CodeProject - 代码之家
    © . All rights reserved.