首页 » iOS编程(第4版) » iOS编程(第4版)全文在线阅读

《iOS编程(第4版)》2.3 编写命令行工具PandomItems

关灯直达底部

RandomItems不是iOS应用,而是命令行工具。命令行工具不用开发复杂的用户界面,所以能集中精力学习Objective-C。本章和第3章的重点是学习Objective-C,第4章再开发iOS应用。

运行Xcode,选择File→New→Project…在新出现的窗口左侧选择OS X下的Application,然后选择右侧面板上方的Command Line Tool(命令行工具),如图2-3所示。单击Next按钮。

图2-3 创建一个命令行工具项目

在新出现的面板中,将项目命名为RandomItems,项目类型选择Foundation(见图2-4)。

图2-4 为项目命名

单击Next按钮,Xcode会提示保存项目。保存好项目,本书之后的项目还会用到RandomItems的部分代码。

RondomItems的第一个版本将创建一个包含4个字符串的数组。数组包含一组按序排列的对象,可以通过索引存取。其他语言可能会将类似的对象称为list(队列)或vector(向量)。数组中第一个对象的索引都是0。

创建数组后,将遍历数组打印所有字符串。Xcode控制台中的输出会类似图2-5所示。

图2-5 控制台的输出

RandomItems中有5个对象:1个NSMutableArray对象,4个NSString对象,如图2-6所示。

图2-6 NSMutableArray对象包含指向NSString对象的指针

在Objective-C中,数组所包含的“对象”并不是对象自身,而只是指向对象的指针。当程序将某个对象加入数组时,数组会保存该对象在内存中的地址。

现在请关注NSMutableArray和NSString。NSMutableArray是NSArray的子类。Objective-C中的类是以层次结构(hierarchy)的形式存在的。除了整个层级结构的根类NSObject外,每个类都有一个且只有一个父类(superclass)并继承其父类的行为。

图2-7展示了NSMutableArray和NSString的一些方法和层级结构。

图2-7 部分类的层级结构

NSObject作为位于层次结构顶部的父类,其职责是实现Cocoa Touch框架中所有对象的基本行为。所有的类都会继承NSObject中的方法和实例变量。NSObject实现了很多方法,其中两个方法是alloc和init(见图2-7)。因此所有的类都可以使用alloc和init方法创建自己的对象。

子类可以通过添加方法和实例变量扩充其继承自父类的行为:

•NSString扩充NSObject的行为,可以存储和处理字符串,也添加了很多方法,如length,可以返回一个字符串的长度。

•NSArray扩充NSObject的行为,可以按索引存取对象(objectAtIndex:),也可以获取存储的对象数量(count)。

•NSMutableArray扩充NSArray的行为,可以动态增加和删除对象。

创建数组并填充字符串

现在开始在代码中使用这些类。在项目导航面板中选择main.m文件,Xcode会在编辑区域打开该文件。读者可以看到,该文件中的部分代码是由Xcode自动生成的,其中的main函数是C(或Objective-C)程序的入口点(entry point)。

删除用NSLog打印“Hello, World!”的那行代码,添加新代码,创建NSMutableArray对象并添加4个字符串,最后释放NSMutableArray对象:

#import

int main(int argc,const char*argv)

{

@autoreleasepool{

// 在这里输入代码

NSLog(@/"Hello, World!/");

//创建一个NSMutableArray对象,并用items变量保存该对象的地址

NSMutableArray*items=[[NSMutableArray alloc]init];

//向items所指向的NSMutableArray对象发送addObject:消息

//每次传入一个字符串

[items addObject:@/"One/"];

[items addObject:@/"Two/"];

[items addObject:@/"Three/"];

//继续向同一个对象发送消息,这次是insertObject:atIndex;

[items insertObject:@/"Zero/" atIndex:0];

//释放items所指向的NSMutableArray对象

items = nil;

}

return 0;

}

加入数组的是NSString对象,可以通过在字符串前添加一个“@”前缀来创建一个NSString对象:

NSString *myString = @/"Hello, World!/";

遍历数组

现在items数组中有4个NSString对象。接下来,遍历数组中的每一个对象并将结果输出至控制台。

可以使用for循环:

for (int i = 0; i < [items count]; i++) {

NSString *item = [items objectAtIndex:i];

NSLog(@/"%@/", item);

}

因为数组的索引是从0开始的,所以计数器i的初始值为0。数组的最后一个索引是对象数量减去1,因此计数器的终值是[items count] - 1(因为计数器是整型,为方便起见写成i < [items count],而不是i <= [items count] - 1)。在循环体中,向数组发送objectAtIndex:消息,根据当前索引获取NSString对象,再输出至控制台。

数组对象所包含的对象个数是一个非常重要的信息。这是因为在获取数组对象所包含的对象时,如果使用的索引大于或等于数组对象所包含对象的个数,程序就会抛出异常(本章结尾处会介绍更多有关异常的知识)。

这段代码当然可以正常工作,但是Objective-C提供了一种更好的遍历数组的语法,称为快速枚举(fast enumeration)。快速枚举比传统的for循环简洁很多,出错概率更低,而且经过编译器的优化,通常比for循环更快。

在main.m中,添加以下代码,使用快速枚举遍历items数组:

int main (int argc, const char * argv)

{

@autoreleasepool {

//创建一个NSMutableArray对象,并用items变量保存该对象的地址

NSMutableArray *items = [[NSMutableArray alloc] init];

//向items所指向的NSMutableArray对象发送addObject:消息

//每次传入一个字符串

[items addObject:@/"One/"];

[items addObject:@/"Two/"];

[items addObject:@/"Three/"];

//继续向同一个对象发送消息,这次是insertObject:atIndex:

[items insertObject:@/"Zero/" atIndex:0];

//遍历items数组中的每一个item

for (NSString *item in items) {

//打印对象信息

NSLog(@/"%@/", item);

}

//释放items所指向的NSMutableArray对象

items=nil;

}

returnO;

}

快速枚举有一个限制:如果需要在循环体中添加或删除对象,就不能使用快速枚举,否则程序会抛出异常。这时只能设置计数器并使用普通的for循环。

构建并运行应用(Command-R),Xcode会在窗口底部显示一个新面板,称为调试区域(debug area)。显示程序输出结果的控制台位于调试区域右侧(见图2-8)。

图2-8 调试区域和控制台

如果需要改变这些面板的大小,可以拖曳调试区域和其下面板的边框。实际上,工作空间中的所有区域都可以通过拖曳边框改变大小。

读者已经完成了RandomItems的第一个版本,在开发下一个版本之前,先学习NSLog函数和格式字符串。

格式字符串

NSLog函数可以将某个指定的字符串输出至Xcode的控制台。此外,NSLog的实参个数并不确定,其中的第一个实参是必需的,且必须是NSString对象。这个实参称为格式字符串(format string)。

格式字符串可以包含文字和多个转换说明(token)。格式字符串中的转换说明(也称为格式规格)必须以百分号(%)为前缀。除了传入NSLog函数的第一个实参,每个额外传入的实参都会替换掉格式字符串中的一个转换说明。

转换说明会指定和其相对应的实参的类型。代码如下:

int a = 1;

float b = 2.5;

char c = /'A/';

NSLog(@/"Integer: %d Float: %f Char: %c/", a, b, c);

上例的控制台输出应该为:

Integer: 1 Float: 2.5 Char: A

Objective-C的格式字符串基本和C语言相同。但是Objective-C支持一种额外的转换说明:%@,对应的实参类型是指向任何一种对象的指针。

程序在处理格式字符串时,如果遇到%@,则不会将其直接替换为相应位置的实参。程序会先向相应位置的实参发送description消息,得到description方法所返回的NSString对象,然后使用得到的NSString对象替换%@。

因为程序会向%@所对应的实参发送消息,所以这些实参必须是对象。请读者回顾图2-7,可以看到NSObject实现了description方法,因此所有的Objective-C对象也都实现了该方法并可以对应%@。