Objective-C基础教程学习笔记(八)Foundation Kit快速教程
Foundation框架只是Cocoa的一部分。
Cocoa Foundataion框架中有很多有用的、面向数据的低级类和数据类型,例如NSString、NSArray、NSEnumerator和NSNumber。Foundation框架拥有100多个类。
一些有用的数据类型
范围的作用
NSRange
typedef struct _NSRange{
unsigned int location;
unsigned int length;
} NSRange;
这个结构体用来表示相关事物的范围,通常是字符串里的字符范围或者数组里的元素范围。location字段存在该范围的起始位置,而length字段则是该范围内所含元素的个数。在字符串“Objective-C is a cool language”中,单词“cool”可以用location为17,length为4的范围来表示。也许由于location字段未被初始化,所以它的值可以是NSNotFound,用来表示无意义范围。
3种方式创建新的NSRange。
1,NSRange range;range.location = 17;range.length = 4;
2,C语言的聚合结构赋值机制 NSRange range = {17,4};
3,Cocoa提供的快捷函数NSMakeRange() NSRange range = NSMakeRange(17,4);
使用NSMakeRange()的好处是你可以在任何能够使用函数的地方使用它,例如方法调用中将其当成参数传递:
[anObject fiarbulateWithRange:NSMakeRange(13,15)];
几何数据类型
NSPoint,NSSize
typedef struct _NSPoint{
float x;
float y;
} NSPoint;
typedef struct _NSSize{
float width;
float height;
} NSSize;
NSRect
typedef struct _NSRect{
NSPoint origin;
NSSize size;
}NSRect;
NSPoint 代表的是笛卡儿平面中的一个点(x,y);
NSSize 用来存储长度和宽度。
NSRect 矩形数据类型,它是由点和大小复合而成的。
Cocoa提供了创建这些数据类型的快捷函数:NSMakePoint()、NSMakeSize()和NSMakeRect()。
为什么这些数据类型是C的struct而不是对象呢?原因归结起来就是因为性能。程序(尤其是GUI程序)会用到许多临时的点、大小和矩形来完成它们的工作。所有的Objective-C对象都是动态分配的,而动态分配是一个代价高的操作,它会消耗大量时间。所以将这些结构创建成第一等级的对象都会在使用过程中增加大量的系统开销。
字符串
NSString
创建NSString
+(id) stringWithFormat:(NSString *) format,...;
省略号:这个方法可以接收多个以逗号隔开的其它参数。
+号:这个方法被定义为类方法。这个方法属于类对象,而不是类的实例对象。
我们称这种用来创建新对象的方法为工厂方法。
length方法,返回字符串的字符个数
-(unsigned int) length;
比较
isEqualToString: 可以用来比较接收方和当作参数传递来的字符串。返回BOOL数据类型表示两个字符串的内容是否相同。
-(BOOL) isEqualString:(NSString *) aString;
比较两个字符串,可以使用compare:方法,声明如下:
-(NSComparisonResult) compare:(NSString *)string;
compare:将接收对象和传递来的字符串逐个字符进行比较,它返回一个NSComparisonResult(enum类型)来显示比较结果:
typedef enum _NSComparisonResult{NSOrderAscending = -1,NSOrderedSame = 0,NSOrderedDescending = 1} NSComparisonResult;
NSString *string1 = @"aardvark";
NSString *string2 = @"tarsier";
BOOL result = [string1 compare: string2] == NSOrderedAscending;
isEqualToString:比较字符串值
==:判断两个字符串的指针数值
不区分大小写的比较
-(NSComparisonResult)compare:(NSString *)sring options:(unsigned) mask;
options参数是一个位掩码。可以使用位或运算积分榜来添加选项标记。常用如下:
NSCaseInsensitiveSearch:不区分大小写字符
NSLiteralSearch:进行完全比较,区分大小写
NSNumericSearch:比较字符串的字符个数,而不是字符值。
if([thing1 compare:thing2 options:NSCaseInsensitiveSearch | NSNumericSearch] == NSOrderedSame){ NSLog(@”They match!“);}
包含字符串
检查字符串是否以另一个字符串开头
-(BOOL) hasPrefix:(NSString *) aString;
检查字符串是否以另一个字符串结尾
-(BOOL) hasSuffix:(NSString *) aString;
检查字条串是否包含其它字符串
-(NSRange) rangeOfString:(NSString *) aString;
可变性
NSString是不可变的,不可变的意思是一旦NSString被创建了,我们就不能改变它。可以对它执行各种各样的操作,例如用它生成新的字符串,查找字符或者将它与其它字符串比较,但是你不能以删除字符或者添加字符的方式来改变它。
Cocoa提供了一个NSString的子类,NSMutableString。如果想改变字符串,使用这个子类。
创建一个新的NSMutableString
+(id)stringWithCapacity:(unsigned)capacity;
-(void)appendString:(NSString *) aString;
appendString 把参数aString 复制到接收对象的末尾。
-(void)appendFormat:(NSString *) format,...;
appendFormat把格式化的字符串附加到接收对象的末尾。
-(void)deleteCharactersInRange:(NSRange) range;
删除字符串中的字符。
由于NSMutableString 是 NSString的子类,所以我们知道两个特性。
第一个就是任何使用NSString的地方,都可以使用NSMutableString来替代。任何接受NSString的方法也都会接受NSMutableString。
另一个特性源于继承,NSMutableString 可以使用NSString的方法。
集合家族
NSArray
NSArray是一个Cocoa类,用来存储对象的有序列表。可以在NSArray中放入任意类型的对象。只要有了一个NSArray,就可以通过各种方法来操作它,例如让某个对象的实例变量指向这个数组,将该数组当作参数传递给方法或函数,获取数组中所存对象的个数,提取某个索引所对应的对象,查找数组中的对象,遍历数组,等等。
NSArray有两个限制。首先,它只能存储Objective-C对象,不能存储C语言中的基本数据类型,如int,float,enum,struct。同时,也不能在NSArray中存储nil(对象的零值或NULL值)。
创建NSArray通过类方法 arrayWithObjects: 。发送一个以逗号分隔的对象列表,在列表结尾添加nil代表列表结束。
查询所存对象的个数
-(unsigned)count;
获取特定索引处的对象
-(id)objectAtObject:(unsigned int) index;
NSRangeException 引用的索引大于数组中对象的个数。
NSCFArray。在Cocoa中,出现“CF”,就看到了与苹果公司的Core Foundation框架相关的内容。Core Foundation框架与Cocoa一样,但它是用C语言实现的,它的大部分代码都是开源的。
将字符串切分成数组
-componentsSeparatedByString:
合并数组的元素创建字符串
-componentsJoinedByString:
可变数组
同NSString一样,NSArray创建是不可变对象的数组。NSArray的补充类NSMutableArray。
+(id) arrayWithCapacity:(unsigned)numItems;
在数组末尾添加对象
-(void) addObject:(id) addObject;
删除特定索引处的对象
-(void) removeObjectAtIndex:(unsigned ) index;
枚举“王国”
你可以编写一个从0到[array count]的循环来读取每个索引处的对象,也可以使用NSEnumerator,它是Cocoa用来描述这种集合迭代运算的方式。要想使用NSEnumerator,需通过objectEnumerator向数组请求枚举器:
-(NSEnumerator *)objectEnumerator:
NSEnumerator *enumerator = [array objectEnumerator];
如果想要从后面向前浏览集合,可以使用reverseObjectEnumerator:方法。
获取枚举器后,可以开始一个while循环,每次循环都向这个枚举器请求它的nextObject(下一个对象):
-(id)nextObject;
nextObject返回nil值时,循环结束。
id thingie;
while(thingie = [enumerator nextObject]){
NSLog(@”I found %@”,thingie);
}
对可变数组进行枚举操作时,有一点需要注意:不能通过添加或删除对象这种方式来改变数组容器。
快速枚举
Objective-C2.0有了新的调整,有一个是“快速枚举”。
for(NSString *string in array){
NSLog(@”I found %@”,string);
}
综上,3种方式遍历数组:通过索引、使用NSEnumerator、快速枚举。
如果只在Leopard或更高版本的操作上运行程序,请使用快速枚举,因为它更简洁快速。
如果程序还需要支持Tiger系统。就使用NSEnumerator。
只有真的需要使用索引访问数组时才应使用-objectAtIndex。
NSDictionary
字典就是关键字及其定义的集合。
NSDictionary在给定的关键字(通常是一个NSString字符串)下存储一个数值(可以是任意类型的对象)。然后你就可以使用这个关键字来查找相应的数值。
为什么不用数组存储然后在数组里查询数值呢?字典(也被称为散列表或关联数组)使用的是键查询的优化存储方式。它可以立即找出要查询的数据,而不需要遍历整个数组进行查找。对于频繁的查询和大型的数据集来说,使用字典比数组要快得多。
NSDictionary就像NSString和NSArray一样是不可变的对象。但是NSMutableDictionary类允许你随意添加和删除字典元素。在创建新的NSDictionary时,就要提供该字典所存储的全部对象和关键字。
+(id) dictionaryWithObjectsAdnKeys:(id) firstObject,...;
该方法接受对象和关键字交替存储的系列,以nil值作为终止符号(所以,不能在NSDictionary中存储nil值)。
使用objectForKey:来获取字典中的值
-(id)objectForKey:(id) aKey;
如果没有查到,objectForKey:会返回nil值。
NSMutableDictionary
+(id) dictionaryWithCapacity:(unsigned int)numitems;(Cocoa命名系统非常规范)
字典容量只是一个建议,而不是对其大小的限制。
使用setObject:forKey:方法给字典添加元素:
-(void) setObject:(id) anObject forKey:(id) aKey;
如果对字典中已有的关键字使用setObject:forKey:,那么这个方法将会用新值替换原有数值。
在可变字典中删除一个关键字,使用removeObjectForKey:方法
-(void) removeObjectForKey:(id) aKey;
各种数值
NSArray和NSDictionary只能存储对象,而不能存储任何基本类型的数据,如int、float或struct。但是可以用对象来封闭基本数值。然后将这个对象放入NSArray或NSDictionary中。
NSNumber
Cocoa提供了NSNumber类来包装基本数据类型。
+(NSNumber *) numberWithChar:(char) value;
+(NSNumber *) numberWithInt:(int) value;
+(NSNumber *) numberWithFloat:(float) value;
+(NSNumber *) numberWithBool:(BOOL) value;
......
-(char) charValue;
-(int) intValue;
-(float) floatValue;
-(BOOL) boolValue;
-(NSString *) stringValue;
通常将一个基本类型的数据包装成对象叫做装箱,从对象中提取基本类型的数据叫取消装箱。
NSValue
NSNumber实际上是NSValue的子类,NSValue可以包装任意值。可以用NSValue将结构放入NSArray和NSDictionary中。
+(NSValue *) valueWithBytes(const void *) value objCType:(const char *) type;
传递的参数是包装的数值的地址。通常,得到的是你想要存储的变量的地址(C语言中使用操作符&)。你也可以提供一个用来描述这个数据类型的字符,通常用来说明struct中实体的类型和大小。你不用自己写代码来生成这个字符串,@encode编译器指令可以接受数据类型的名称并为你生成合适的字符串。所以按照以下方式把NSRect放入NSArray中:
NSRect rect = NSMakeRect(1,2,30,40);
NSValue *value;
value = [NSValue valueWithBytes:&rect objCType:@encode(NSRect)];
[array addObject:value];
使用getValue:提取数值:
-(void) getValue:(void *)value;
Cocoa提供了将常用的struct型数据转换成NSValue的便捷方法,如:
+(NSValue *) valueWithPoint: (NSPoint) point;
+(NSValue *) valueWithSize:(NSSize) size;
+(NSValue *) valueWithRect:(NSRect) rect;
-(NSPoint) pointValue;
-(NSSize) sizeValue;
-(NSRect) rectValue;
NSNull
空值 NSNull大概是Cocoa里最简单的类了,它只有一个方法:
+(NSNull *) null;
[NSNull null] 总是返回一样的数值,所以你可以使用运算符==将该值与其它值进行比较。
示例:查找文件
功能描述:翻查主目录,查找.jpg文件并输出找到的文件列表。
用到NSString、NSArray、NSEnumerator以及其它两个用来与文件系统交互的Foundation类。
示例还用到了NSFileManager,它允许你对文件系统进行操作,如创建目录、删除文件、移动文件或者获取文件信息。我们将会要求NSFileManager为我们创建NSDirectoryEnumerator来遍历文件的层次结构。
......
//获取NSFileManager对象。
NSFileManager *manager;
manager = [NSFileManager defaultManager];
//确定从文件系统中的什么位置开始查找文件。
NSString *home;
//Unix系统有一个代表主目录的速记符号~(也称为代字符)。
//NSString中有一个方法可以接受~字符并将其展开。该方法将~替换成当前用户的主目录。
home = [@”~” stringByExpandingTildelInPath];
//将路径字符串传递给文件管理器
NSDirectoryEnumerator *direnum;
direnum = [manager enumeratorAtPath:home];
NSMutableArray *file;
files = [NSMutableArray arrayWithCapacity:42];
NSString *filename;
while(filename = [direnum nextObject]){
//方法 pathExtension输出文件的扩展名(不包含前面的.)
if([[filename pathExtension] isEqualTo:@”jpg”]){
[files addObject:filename];
}
}
NSEnumerator *fileenum;
fileenum = [files objectEnumerator];
while(filename=[fileenum nextObject]){
NSLog(@“%@”,filename);
}
......