此文档将通过创建一个货币转换器应用程序(CurrencyConverter),讲述在Mac操作系统下开发应用程序的基本流程。
1、打开 Xcode
在 /Developer/Applications/ 中找到 Xcode。双击图标,如图示 1 所示,打开Xcode。
图示 1 Xcode 应用程序图标
2、选择新建项目命令
当 Xcode 运行时,只有菜单被显示。要创建项目,从文件菜单中选择新建项目。Xcode 将显示新建项目窗口。
3、选择项目类型
Xcode 可以创建不同种类的应用程序,包括 Cocoa 应用程序到 Mac OS X 核心扩展,以及 Mac OS X 架构。选择 Cocoa 应用程序并点击下一步,如图示 2 所示。
如图示 3 所示,点击选取以浏览到您想保存项目的目录。在项目名称文本框中输入项目的名称。对于当前的项目,输入“CurrencyConverter” 。注意名称中不可有空格。点击结束。
图示 3 在 Xcode 新建项目助手中选取名称和位置
点击结束后,Xcode 创建并显示一个项目窗口,通过左边的 “ Group&File” 窗口,我们可以查看项目相关的文件和资源,如图示 4 所示,它们主要分为:
【1】、CurrencyConverter :选中它,在右边的列表中则显示出该项目中相关的文件。如图示 4 所示 ,以本项目为例,这些文件包括:
(1)、English.lproj :包含您所偏爱的语言的本地化资源的目录。nib 文件自动生成在该目录中。您也许会发现其他本地化资源,比如 Dutch.lproj。要获得有关 nib 文件的更多信息,请参阅界面生成器的开发人员文档。
(2)、Main.m :存在于任何项目中,包含应用程序的入口点代码。
(3)、Info.plist 、version.plist : 存在于任何项目中,包含项目重要信息的两个文件。您永远不会直接编辑它们,它们的内容是通过 Xcode 中的设置改变的。
(4)、CurrencyConverter_Prefix.pch :该文件包含一个常用的并会被 Xcode 预编译的头文件包含列表。如果使用得当,预编译可以帮助减少编译时间。请参阅 Xcode 的联机帮助获得更多信息。
(5)、CurrencyConverter.pbproj :该文件包含定义项目的信息。您不应该直接修改它。您可以通过在 Finder 中双击该文件打开项目。
【2】、Targets :列出您构件中所有的最终结果。该组通常包含一个目标,比如:一个应用程序,或一个架构,但它也能够包含多个项目。
【3】、Executables :包含项目中所有可执行的程序
【4】、Error and Warnings :显示项目在生成过程中遇到的错误和警告。
图示 3-4 在 Xcode 中新建的货币转换器项目。
【5】、nib 文件 :图形界面的资源文件,类似于 Windows 程序开发项目中的 .rc 文件。它包含菜单条,并通常至少有一个包含其他不同对象的窗口。在本例子项目中的资源子组中定位 MainMenu.nib。 双击打开它。界面生成器会被打开,nib 文件会被调出。当 nib 文件打开时,如图示 5 ,一个默认的菜单条以及一个标题为 “Window” 的窗口会出现。
图示 5 界面生成器中一个可调节大小的窗口
4、完成窗口布局
根据需要,布局转换器的界面。应用程序的窗口如图示 6 所示。
图示 6 界面生成器中货币转换器的最终用户界面
5、指定子类
必须通过 nib 文件窗口中类视图中定义一个类。让我们从 ConverterController 类开始。在界面生成器中,选择 MainMenu.nib 窗口的类面板。 如图示 7 ,在面板最左边的栏中,点击 NSObject并按下回车以创建一个叫 MyObject 的 NSObject 子类。 键入 “ConverterController” 更名并按下回车键锁定。
图示 7 创建子类 NSObject
6、定义类的出口
在界面生成器中,指定 ConverterController 对象和其它对象之间的信息传播路径为 出口( Outlets ) 和 动作( Actions )。如图示 8 ,从类窗口中选取 ConverterController ,
选择 “ 0 Outlets ” ,点击 “ add ” 按钮。
图示 8 界面生成器信息窗口中的出口和动作
命名该出口( Outlets )为 rateField 并按下回车键。此时 rateField 出口仍被选定,我们可以按下回车键来创建更多的出口;依此法创建 dollarField 出口和 totalField 出口。
注意出口表中的类型栏。出口类型被默认地设置为 id。 通过选择当前设为 id 的组合框列表来更改三个出口的类型为 NSTextField。
ConverterController 需要访问界面中的文本框,所以您要提供用于此目的的出口。 但同时 ConverterController 必须也要和 Converter 类(尚未定义)进行通信。要激活这个通信, 为 ConverterController 增加一个名为 converter 的出口。
7、定义类的动作
ConverterController 有一个动作方法 —— " convert:" ;当用户点击转换按钮时,一个 convert:消息被发送到目标对象 —— ConverterController 的实例。 动作既与当用户点击一个按钮,或操作一些其它控件对象时的对象有关, 也与被调用的方法有关。
如图示 8 ,选择 “ 0 Action ” ,点击 “ add ” 按钮。输入方法的名字,convert,然后按下回车键。界面生成器自动为您加上“:”。
8、生成类的一个实例
这是在界面生成器中定义一个类的最后一步,创建类的一个实例并连接它的出口和动作。在类窗口中选择 ConverterController(如果它没有事先被选中)。 从类菜单中选取“ Instances ” , 这个实例将会出现在实例视图中,如图示 9 所示。注意:该实例旁边有一个检查点,这说明这里有您必须要连接的已定义的出口。
图示 9 界面生成器中新初始化的 ConverterController 对象
9、连接自定义类到界面
现在连接 ConverterController 对象到用户界面。通过在界面中把它连接到特定的对象,我们可以初始化它的出口。 ConverterController 将使用这些出口获得和设置界面中的值。
如图示10,在 nib 文件窗口的实例面板中,按下 Control 键从ConverterController 实例中拖拽一个连接线到第一个文本框。当文本框出现轮廓线时,放开鼠标按键。 界面生成器将调出信息窗口的连接面板。
选择第一个文本框的轮廓,rateField,点击“ Connect ”按钮。
图示 10 连接 ConverterContorller 到 rateField 的轮廓
按照同样的步骤,连接 ConverterController 的 dollarField 和 totalField 到相应的文本框。
10、连接界面控件到类的动作
在 nib 文件窗口中按下 Control 键从转换按钮拖拽一个连接到 ConterterController 实例。当实例出现轮廓时,放开鼠标按键。
在连接面板中,确定出口栏中的 target 被选定。 在动作栏中选择 “ convert ”。 点击“ Connect ” 按钮。 设置完成后,保存 nib 文件。
11、定义 Converter 类
当连接 ConverterController 轮廓时,我们仍有一个出口没有连接:converter。 这个出口指明了货币转换应用程序中 Converter 类的一个实例,但这个实例还不存在。
Converter 是模式-视图-控制器模式中的模式类。这种类型的类不直接和界面通信,因此没有出口和动作。我们可以根据以下步骤完成它的定义:
【1】、在类的视图中,创建一个 NSObject 的子类 Converter。
【2】、初始化 Converter 类。
【3】、创建 ConverterController 和 Converter 之间的出口连接。(按下 Control 键从 ConverterController 实例拖拽到 Converter 实例。)
【4】、保存 MainMenu.nib。
现在,所有关于界面的工作都完成了。接下来就是实现应用程序功能部分了。
12、生成源文件
转到 nib 文件窗口中的类面板,选择ConverterController 类,从类菜单中选择创建文件命令。 确认 .h 和 .m 旁的创建栏的检查框被选定。确认包含文件到 CurrencyConverter 目标的检查框被选定。 如果该检查框未出现,也许是因为先前未 nib 文件。 保存 nib 文件并重复以上步骤。 点击 “ Choose ” 按钮。 为 Converter 类重复以上步骤。 保存 nib 文件。然后退出界面生成器。
13、消息( Message )与方法( method )的实现
方法是类为它的对象实现的过程。方法可以是 public 或者 private;public 方法在类的头文件中定义。消息是对象方法的调用,其通过名字来确定方法。
消息表达式包含一个确定接收对象的变量,以及跟随其后的我们想调用的方法;表达式被包含在括号中。
[anObject doSomethingWithArg:this];
如同标准 C 一样,终止符是一个分号。
通常地,消息将导致由被调用方法的返回值;必须在赋值式的左边要有一个正确类型的变量来接收这个值。
int result = [anObj calcTotal];
我们可以在其它消息表达式中嵌套消息表达式。 这个例子取得了一个表单对象的窗口,然后将其返回的 NSWindow 对象作为另一个消息。
[[form window] makeKeyAndOrderFront:self];
一个方法使用类似一个函数的方式组织。在方法的完全声明之后是包含在括号中的实现代码方法体。
使用 nil 来指明一个 null 对象; 这类似于一个 null 指针的情况。 注意一些 Cocoa 方法不接收 nil 作为参数。
一个方法可以有效地应用两个隐式标识: self 和 super。 两者均指明接受消息的对象,但它们的不同之处在于方法的实现在何处: self 从接收方的类开始搜索,而 super 从接收方的父类开始搜索。因此,
[super init];
使得父类的 init 方法被调用。
在方法中,可以直接访问类实例中的实例变量。但是,推荐使用访问子(accessor)方法,而不要直接访问, 除非是在考虑到效率因素是极为重要的地方。
14、声明
声明动态类型对象为 id:
id myObject;
由于动态类型对象的类是在运行时刻决定的,所以可以在不知道其归属的前提下引用它们。 如果出口和对象可能参与多态和动态绑定,按照此方法定义其类型。
作为类指针的静态类型对象:
NSString *mystring;
可以通过静态定义对象的类型来获得编译时刻更好的类型检查以及更易读的代码。以一个负号(-)开始来定义实例方法;负号后的空格是可选的。
- (NSString *)countryName;
如刚才的例子所示,在负号(或正号)和方法的开头部分放上括号中方法返回值的类型。 如果方法没有返回,那么它的返回类型是 void。
方法参数类型处于括号中,并且位于参数关键字与参数本身之间:
- (id)initWithName:(NSString *)name andType:(int)type;
确定所有的声明都以分号结尾。
通常默认实例变量的范围是 protected,只有声明它的类的对象,或者这个类的子类可以直接访问。 要使实例变量为 private (只在声明类中可访问),在声明前插入 @private。
15、添加方法声明
可以在由界面生成器生成的头文件中增加实例变量或方法的声明。对于本例子,我们需要增加一个被 ConverterController 对象调用的方法以取得计算的结果。现在开始在 Converter.h 声明方法。
如图示 11 ,在工具栏中按下编辑器按钮以拆分开窗口进入编辑模式。
图示 11 Xcode 中的编辑器按钮
在窗口右边的项目浏览器中高亮显示类子组文件夹像标并选择 Converter.h ,为 convertAmount:atRate: 插入一个声明。
class=WF#import <Cocoa/Cocoa.h>
@interface Converter:NSObject
{
}
- (float)convertAmount:(float)amt atRate:(float)rate;
@end
这个声明规定了 convertAmount:atRate: 接受两个 float 类型的参数,并返回一个 float 值。当方法名字的一部分含有冒号时,比如 convertAmount:、atRate:,它们是引入参数的关键字。 (这里的关键字与“C”语言中的含义不同。)
16、实现货币转换器的类
对于 Converter 类,实现我们在 Converter.h 中声明的方法,方法实现放在 @implementation <class name> 和 @end 之间,这是为 Converter 添加代码的地方。
【1】、从 Xcode 主窗口中的类组选择 Converter.m 。
【2】、为 convertAmount: 插入代码:
class=WF#import "Converter.h"
@implementation Converter
- (float)convertAmount:(float)amt atRate:(float)rate
{
return (amt * rate);
}
@end
这个方法简单地操作两个参数并返回结果。十分简单。
【3】然后,更新界面生成器为您生成的 ConverterController.m 中 convert: 的“空”实现。
class=WF- (IBAction)convert:(id)sender
{
float rate, amt, total;
amt = [dollarField floatValue];
rate = [rateField floatValue];
total = [converter convertAmount:amt atRate:rate];
[totalField setFloatValue:total];
[rateField selectText:self];
}
为在 ConverterController.m 导入 Converter 类,确认在源文件的顶部加入下列行。
class=WF#import "Converter.h."
这样,我们通过convert: 方法做了以下事情:
(1)、取得在汇率和美元数目文本框中输入的浮点值。
(2)、调用 convertAmount:atRate: 方法并取得返回值。
(3)、使用 setFloatValue: 在其它货币文本框(totalField)中写入返回值的数量。
(4)、发送 selectText: 到汇率文本框;选取框中的文本,如果没有文本, 插入光标以 便用户开始下一次计算。
convert: 方法中除了浮点数声明的每一行都是消息。 在消息表达式左边的“字”指明了接收消息的对象(称之为接收方)。 这些对象由我们定义并连接的出口来识别。 在接收方的后面,是发送对象(称之为发送方)想要调用的方法的名字。 消息经常就是返回的值;在上述的例子中,本地变量 rate,amt,以及 total 拥有这样的值。
在生成项目之前,在 ConverterController.m 内加入一小段代码将有助于程序用户的使用。 当应用程序启动时,如果希望货币转换器窗口被选中,并且光标在每美元汇率文本框内。 我们只能在 nib 文件展开后才能这样做,因为这样才建立了与文本框 rateField 之间的连接。 要建立这样的设置操作,需要在展开结束时发送 awakeFromNib 到所有的对象。 实现这个方法以获得合适的动作。
在 ConverterController.m 中加入以下代码。
class=WF- (void)awakeFromNib
{
[[rateField window] makeKeyAndOrderFront:self];
[rateField selectText:self];
}
就像消息 makeKeyAndOrderFront: 的名字所暗示那样: 它使得接收窗口成为 key 窗口(可以从键盘接受输入的窗口),并且把它放在屏幕上所有其它窗口的前面。 这个消息也嵌套了其它消息,[rateField window]。 该消息返回文本框所在的窗口,然后 makeKeyAndOrderFront: 方法被传送到这个返回对象。
那么,现在货币转换器的程序实现部分就完成了。
17、生成应用程序
点击 Xcode 中的生成按钮运行生成工具。 生成工具协调产生一个可执行文件的编译和链接过程。它也执行要生成应用程序所需的其它任务。这个过程包括:
生成工具调用编译器,传给它项目的源文件。编译这些文件(Objective-C,C++ 以及标准 C)产生机器可读的,特定体系结构的目标文件。
在生成的链接阶段,生成工具执行链接器,传给它库和架构来连接目标文件。 架构和库包含预先编译好的,可以用于任何应用程序的代码。链接整合了库、架构以及目标文件中的代码来产生可执行文件。
生成工具拷贝 nib 文件、声音、图像以及其它项目中的资源到应用程序包中适当的本地化或非本地化位置。 一个应用程序包是一个包含应用程序执行程序及其所需资源的目录。 该目录在 Finder 中以单一文件出现,可通过双击来启动它。
18、生成项目
通过点击生成按钮开始生成过程。保存源代码文件和任何项目中的改变。 在 Xcode 窗口中点击生成按钮,如图示 12 所示。
图示 12 Xcode 中的生成按钮
生成过程开始后, 工具条下的信息行将显示生成的运行状态。当 Xcode 结束并且在生成过程中没有任何错误时 —— 它在信息行显示“生成成功”。
19、调试项目
如果 Xcode 在生成应用程序时检查到代码有错误。那么我们可以从代码左边的栏中观察到代码包含错误(表示为一个红色的停止符)以及警告(表示为黄色警告符)的个数。
通过带颜色的符号我们可以了解错误的位置,同时在 “ Group & File ” 列表中,点击错误与警告组旁的三角(如果它事先没有指向下方的话)。 可以看到发生错误或警告的相关文件列在该组中。点击错误与警告组中的文件就可以显示错误以及错误原因。
Xcode 还提供了 GNU 调试器 GDB 的图形用户界面。 我们可以使用它来跟踪货币转换器的代码。
【1】、点击类组,并选择 Xcode 中组 & 文件列表右边的组文件列表中 ConverterController.m。
【2】、找到 convert: 方法。
【3】、如图示 13 ,在代码清单左边的栏中点击 rate 赋值表达式设置断点。
图示 13 在 Xcode 中设置断点
【4】、通过从生成与运行菜单中选择调试命令(或按下 Command-R)来运行调试器.
【5】、输入值并点击转换按钮测试转换功能。
此时应用程序隐藏,调试器出现。 检查调试器窗口右边变量列表中局部变量的值。 rate and amt 对应我们在文本框中输入的数值。 注意,total 中的值是不正确的。
左边的栏中的红箭头显示当前应用程序运行的位置。它还未完成 total 的计算;所以是个不正确的值。现在点击跳过按钮。调试器完成语句并且相乘的结果保存在 total 变量。代码工作正确。
当程序表现异常时,跟踪代码是很有用的。通过单步跟踪的手段,可以在代码运行阶段更好地判断问题出现在何时,并决定如何修正它。
要执行复杂的调试任务,可以使用 GDB 的控制台。 点击窗口右上角的 Console Drawer 按钮打开控制台。当在 Console Drawer 中点击鼠标并按下回车后,(gdb) 的提示符会出现。
在该提示符中可以输入许多用户界面中没有提供的 GDB 命令。如果想要得到这些命令的在线信息,可以在提示符中输入 “help” 。
调试结束,关闭调试窗口并在 Xcode 工具条中点击停止按钮结束调试器。
20、运行程序
打开生成并运行菜单,选择运行命令,即可运行程序。