第15章 数字、字符串和集合

本章讲解了如何使用Foundation框架提供的一些基本对象。这些基本对象包括数字、字符串和集合,集合指的是能够以数组、字典和集的形式使用成组对象的能力。

Foundation框架包括大量可供使用的类、方法和函数。在Mac OS X上,大约有125个可用的头文件。作为一种简便的形式,可以简单地使用以下语句导入:


import<Foundation/Foundation.h>


因为Foundation.h文件实际上导入了其他所有Foundation头文件,因此不必担心是否导入了正确的头文件。Xcode会自动将这个头文件插入程序中,正如你在本书的每个示例中所见到的。

使用这条语句会显著地增加程序的编译时间。然而,通过使用预编译的头文件,可以避免这些额外的时间开销。预编译的头文件是经过编译器预先处理过的文件。默认情况下,所有Xcode项目都会受益于预编译的头文件。

本章使用的每个对象都将用到这些特定的头文件。这有助于你熟悉每个头文件所包含的内容。

注意如果喜欢,可以继续导入语句Foundation.h,如果确实导入了每个例子中显示的单个文件,还应该删除Project_name_prefix.pch文件,该文件是在创建新的Foundation Tool项目时Xcode自动包含进去的。在从项目中删除文件时,需要确保在Xcode提示时选择Delete Reference。

15.1 数字对象

到目前为止,我们所讨论过的所有数字数据类型,如int型、float型和long型都是Objective-C语言中的基本数据类型,也就是说,它们都不是对象。例如,不能向它们发送消息。然而,有时需要作为对象使用这些值。例如,使用Foundation的对象NSArray,可以设置一个用于存储值的数组。这些值必须是对象,因此不能将任何基本数据类型直接存储到这些数组中。要存储任何基本数据类型(包括char数据类型),可以使用NSNumber类根据这些数据类型来创建对象(参见代码清单15-1)。

代码清单15-1


//Working with Numbers

import<Foundation/NSObject.h>

import<Foundation/NSAutoreleasePool.h>

import<Foundation/NSValue.h>

import<Foundation/NSString.h>

int main(int argc, char*argv[])

{

NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];

NSNumbermyNumber,floatNumber,*intNumber;

NSInteger myInt;

//integer value

intNumber=[NSNumber numberWithInteger:100];

myInt=[intNumber integerValue];

NSLog(@“li”,(long)myInt);

//long value

myNumber=[NSNumber numberWithLong:0xabcdef];

NSLog(@“l x”,[myNumber longValue]);

//char value

myNumber=[NSNumber numberWithChar:‘X’];

NSLog(@“c”,[myNumber charValue]);

//float value

floatNumber=[NSNumber numberWithFloat:100.00];

NSLog(@“g”,[floatNumber floatValue]);

//double

myNumber=[NSNumber numberWithDouble:12345e+15];

NSLog(@“lg”,[myNumber doubleValue]);

//Wrong access here

NSLog(@“i”,[myNumber integerValue]);

//Test two Numbers for equality

if([intNumber isEqualToNumber:floatNumber]==YES)

NSLog(@“Numbers are equal”);

else

NSLog(@“Numbers are not equal”);

//Test if one Number is<,==,or>second Number

if([intNumber compare:myNumber]==NSOrderedAscending)

NSLog(@“First number s less than second”);

[pool drain];

return 0;

}


代码清单15-1输出


100

abcdef

X

100

1.2345e+19

0

Numbers are equal

First number is less than second


使用NSNumber类中的对象时,接口文件<Foundation/NSValue.h>是必需的。

自动释放池一览

代码清单15-1中的第一个程序行在本书中的任何一个程序中都会出现。下面这行代码为你分配给pool的自动释放池(autorelease pool)预留了内存空间:


NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];


自动释放池可以自动释放添加到该池中的对象所使用的内存。向对象发送一条autorelease消息时,就将该对象放到这个池中。释放这个池时,添加到该池的所有对象也会一起释放。因此,所有这样的对象都会被销毁,除非已指明这些对象所在的作用域超出自动释放池(如,使用引用计数指明)。

一般来说,无须担心需要释放Foundation方法返回的对象。有时候,对象由返回它的方法所拥有。其他情况下,对象是由方法新创建的并被添加到自动释放池中。第一部分中讲过,使用完用alloc方法显式地创建的任何对象(包括Foundation对象)之后,仍然需要释放它们。

注意此外,还需要释放由复制行创建的对象,这部分内容将在第17章介绍。

第17章将十分详细地讲述引用计数和自动释放池。

回到代码清单15-1。NSNumber类包含多个方法,它们允许使用初始值创建NSNumber对象。例如,程序行:


intNumber=[NSNumber numberWithInteger:100];


创建了一个值为100的整数对象。

从NSNumber对象获得的值必须和存储在其中的值类型一致。因此,在程序中该语句之后的printf语句中,消息表达式


[intNumber integerValue]


检索存储在intNumber中的整型值,并将其存储在NSInteger变量myInt中。注意,NSInteger不是一个对象,而是基本数据类型的typedef。它被typedef成64位的long或者32位的int。存在一个类似的NSInteger typedef用于处理程序中那些未签名的整数。

在NSLog调用中,将NSInteger转换为long并使用格式字符%li,以确保值可以传递并正确显示,即使程序编译后是32位架构的。

对于每个基本值,类方法都为它分配了一个NSNumber对象,并将其设置为指定的值。这些方法以numberWith开始,之后是该方法的类型,如numberWithLong:、numberWithFloat:等。此外,可以使用实例方法为以前分配的NSNumber对象设置指定的值。这些都是以initWith开头的,如initWithLong:和initWithFloat:。

表15-1列出了为NSNumber对象设置值的类和实例方法,以及检索这些值的相应实例方法。

第15章 数字、字符串和集合 - 图1

回到代码清单15-1,该程序接下来使用类方法创建了long、char、float和double NSNumber对象。注意,使用程序行


myNumber=[NSNumber numberWithDouble:12345e+15];


创建double对象后将出现什么情况?然后尝试(不正确地)使用如下程序行来检索并显示它的值:


NSLog(@“i”,[myNumber integerValue]);


将得到以下输出:


0


并且,系统也没有给出出错消息。一般来说,你负责确保正确地进行检索,如果在NSNumber对象中存储了一个值,那么也要用一致的方式进行检索。

在if语句中,消息表达式


[intNumber isEqualToNumber:floatNumber]


使用isEqualToNumber:方法根据数值比较两个NSNumber对象。该程序测试返回的Boolean值,以查看这两个值是否相等。

可用compare:方法来测试一个数值型的值是否在数值上小于、等于或大于另一个值。消息表达式


[intNumber compare:myNumber]


在intNumber中的值小于myNumber中的值时,返回值NSOrderedAscending;如果这两个数相等,则返回值NSOrderedSame;如果第一个值大于第二个值,则返回值NSOrderedDescending。在头文件NSobject.h中已经定义了这些返回值。

应该注意不能重新初始化前面创建的NSNumber对象的值。例如,不能使用下面的语句设置存储在NSNumber对象myNumber中的整数:


[myNumber initWithInt:1000];


当程序执行时,这条语句将产生一条错误。所有数字对象都必须是新创建的,这意味着必须对NSNumber类调用表15-1第一列列出一个方法,或者对alloc方法的结果调用第二列列出的方法中,如下所示:


myNumber=[[NSNumber alloc]initWithInt:1000];


当然,基于前面的讨论,如果使用这种方式创建myNumber,则在使用完之后,你需要使用以下语句来释放它:


[myNumber release];


本章其余部分将再次在程序中遇到NSNumber对象。