1、数据类型
1)范围
第一个是结构体,表示相关事物的范围,通常是字符串里的字符范围或者数组里的元素范围。
1 typedef struct _NSRange 2 { 3 unsigned int location;//存放该范围的起始位置 4 unsigned int length;//该范围所含元素个数 5 }NSRange;
例如:"Object-c is a cool language"中,单词cool可以用location为17,length为4的范围表示;location还可以用NSNotFound这个值来表示没有范围,说明变量没有初始化。
创建NSRange有三种方法:
(1)直接给字段赋值;
1 NSRange range; 2 range.location = 17; 3 range.length = 4;
(2)应用C语言的聚合结构赋值机制
1 NSRange range = {17,4};
(3)cocoa提供的快捷函数 NSMakeRange(): 可以在任何能够使用函数的地方使用它,例如在方法中调用将其作为参数传递;
1 NSRange range = NSMakeRange(17,4); [anObject flabulateWithRange:NSMakeRange(13,15)];
2、创建字符串
NSString 的 stringWithFormat:方法就是这样通过格式字符串和参数来创建NSString
1 +(id)stringWithFormat:(NSString *)format,-;
可以按照如下方式来创建一个新的字符串:
1 NSString *height; 2 height = [NSString stringWithFormat:@"Your height is %d feet,%d inches",5,11];
得到的字符串是"Your height is 5 feet,11 inches"
3、类方法
stringWithFormat:的声明中,第一个定义最后的省略号(...):可以接受多个以逗号隔开的其他参数。
前置减号(-)的方法为实例方法,必须使用类的实例才可以调用的。
1 -(NSUInteger)length; 2 //也可以这样使用它 3 NSUInteger length = [height length]; 4 //表达式中使用 5 if([height length > 35]) 6 { 7 NSLog(@"wow,you'r really tall."); 8 }
5、字符串比较
(1)isEqualToString:可以用来比较接收方和作为参数传递过来的字符串。返回一个Bool值(YES或NO)来表示两个字符串的内容是否相同。它们的声明如下:
1 //声明 2 -(Bool)isEqualToString:(NSString *)aString; 3 //下面是它的使用方法 4 NSString *thing1 = @"hello 5"; 5 NSString *thing2 = [NSString stringWithFormat:@"hello %d",5]; 6 7 if([thing1 isEqualToString : thing2]) 8 { 9 NSLog(@"They are the same."); 10 }
要比较两个字符串,可以使用compare:方法,其声明如下:
1 //声明 2 -(NSComparisomResult)compare:(NSString *)aString; 3 4 //compare:将接受对象和传递过来的字符串逐个进行比较,返回NSComparisonResult来显示比较结果。 5 emun 6 { 7 NSOrderedAscending = -1; 8 NSOrderedSame , 9 NSOrderedDescending 10 }; 11 typedef NSInreger NSComparisonResult;
补充说明:
比较两个字符串是否相等时,应该使用isEqualToString而不能紧急比较字符串的指针值,因为==运算符只判断thing1和thing2的指针值,而不是他们所指的对象。由于thing1和thing2是不同的字符串,所以第二种方式会认为他们不同的,举个例子:
1 //检查两个对象(thing1和thing2)是否相等,用isEqualToString 2 if([thing1 isEqualToString : thing2]) 3 { 4 NSLog(@"They are the same."); 5 } 6 7 //不同于 8 //检查两个对象(thing1和thing2)是否是同一个事物 9 10 if(thing1==thing2]) 11 { 12 NSLog(@"They are the same."); 13 }
6、不区分大小写的比较
compare:区分大小写的比较;
NSCaseInsensitiveSearch:不区分大小写字符;
NSLiteralSearch:进行完全比较,区分大小写字符;
NSNumericSearch:比较字符串的字符个数,而不是字符串值。
例如:
1 //比较字符串,忽略大小写并按照字符个数进行排序 2 if([thing1 compare thing2 options:NSCaseInsensitiveSearch | NSNumericSearch == NSOrderedSame]) 3 { 4 NSLog(@"They match."); 5 }
7、字符串内是否还包含别的字符串
例如你想知道某个文件名的后缀名是否是.mov 这样就知道能否打开QuickTime Player打开它;
有两个方法可以判断:检查字符串是否以另一个字符串开头;判断字符串是否以另一个字符串结尾;
1 -(Bool)hasPrefix : (NSString *)aString; 2 -(Bool)hasSuffix : (NSString *)aString; 3 4 //你可以使用以下两个方法 5 NSString *fileName = @"draft-chapter.pages"; 6 7 if([fileName hasPrefix:@"draft"]) 8 { 9 //this is a draft 10 } 11 if([fileName hasSuffix:@".mov"]) 12 { 13 //this is a movie 14 }
如果你想知道,字符串内的某处是否包含其他字符串,可以使用rangeOfString:
1 -(NSRange)rangeOfString:(NSString *)aString;
将rangeOfString:发送给一个NSString对象时,传递的参数是要查找的字符串。它会返回一个NSRange结构体,告诉你与这个字符串匹配的那部分在哪里以及能够匹配上的字符个数,如下:
1 NSRange range = [fileName rangeOfString:@"chapter"];
返回的range.location为6,range.length为7.如果传递的参数在接受字符串中没找到,那么range.location则等于NSNoFound。
8、可变的
NSString 是不可变的(一旦被创建,就不能改变。但可以对他指向各种操作,如生成新字符串、查找字符,或将它与其他字符串进行比较,但是不能以删除字符或者添加字符的方式改变它)。
Cocoa提供了一个NSString的子类,叫NSMutableString。如果想要改变字符串,可以使用子类。
可以使用类方法stringWithCapacity:来创建一个新的NSMutableString,声明如下:
1 NSMutableString *string = [NSMutableString stringWithCapacity:42];
一旦有了一个可变字符串,就可以执行各种操作,一种常见的操作是通过appendString:或appendFormat:来附加新字符串,如下所示:
1 //通过appendString:或者appendFormat:来附加新的字符串 2 -(void)appendString:(NSString *)aString; 3 -(void)appendFormat:(NSString *)fomat,...; 4 5 //appengString:接收参数aString然后将其复制到接收对象的末尾 6 //appengFormat:将格式化的字符串附加在接收字符串末尾 7 NSMutableString *string = [NSMutableString stringWithCapacity:50]; 8 [string appengString:@"Hello there "]; 9 [string appengFormat:@"human %d. ",39]; 10 //这段代码最后结果string被赋值为"Hello there human 39."
删除字符串:deleteCharactersInRange:
1 -(void)deleteCharactersInRange:(NSRange)aRange;
例如:假设你列出了所有朋友的名字,但又觉得不太喜欢Jack了,先把他从列表中删除.
1 //创建朋友列表 2 NSMutableString *friends = [NSMutableString stringWithCapacity:50]; 3 [friends appendString: @"james BethLynn jack Evan"]; 4 5 //找到Jack的名字在字符串的范围 6 NSRange jackRange = [friends rangeOfString:@"jack"]; 7 jackRange.length++; 8 9 //把Jack从圣诞卡名单上踢掉 10 [friends deleteCharactersIntange: jackRange]; 11 //如此,字符串变为"james BethLynn Evan"
9、枚举
NSArray经常对数组中的每个元素都执行同一个操作。比方说,你喜欢绿色,可以让数组中所有几何形状都变绿色。你可以编写一个从0到[array count]的循环来读取内个索引处的对象,也可以使用NSEnumerator,Cocoa可以用它来表示集合中迭代出的对象。使用NSEnumerator,需要通过objectEnumerator想数组请求枚举器:
1 -(NSEnumerator *)objectEnumerator; 2 //你也可以使用这个方法 3 NSEnumerator *enumerator = [array objectEnumerator]; 4 //如果你想要往前浏览某个集合,还有一个reverseObjectEnumerator方法可以使用 5 6 //在获得枚举器后,可以开始一个while循环,每次循环都向这个枚举请求它的nextObject(下一个对象): 7 -(id)nextObject; 8 //nextObject返回nil值时,循环结束 9 //循环代码如下 10 NSEnumerator *enumerator = [array objectEnumerator]; 11 while(id thingie = [array objectEnumerator]) 12 { 13 NSLog(@"I found %@",thingie); 14 }
对于可变数组进行枚举操作时,需注意:不能通过添加或者删除对象这个类型方式来改变数组的容量,如果删除了,枚举器会出现混乱,获得未定义的结果(undefined result)“唉,好像重复了”或“噢,我的程序崩溃了”。
快速枚举(fast enumeration)
1 for (NSString *string in array) 2 { 3 NSLog(@"I found %@",string); 4 }
这个循环体将遍历数组中的每一个元素,并用变量string来存储每个数组值。
补充一个能在NSArray中通过代码块枚举对象的方法:
//添加一个能在NSArray中通过代码块枚举对象的方法 -(void)enumerateObjectsUsingBlock:(void(^)(id obj,NSUInteger idx,BOOL *stop))Block; //看不懂没关系,可以用之前的那个数组要重写这个枚举方式 [array enumerateObjectsUsingBlock:^(NSString *string, NSUInteger idx,BOOL *stop){ NSLog(@"I found %@",string); }];
10、NSDictionary
字典(dictionary)是关键字及其定义的集合。Cocoa中实现这种功能的集合类NSDictionary;NSDictionary能在给定的关键字下存储一个数值,然后用这个关键字来查找相应的数据。因此,有了有了存储某人所有联系方式的NSDictionary,那你可以对这个字典说“给我关键字home-address下的值”或者“给我关键字 email-address”下的值。
说明:字典使用的是键查询的优化方式,它可以立即查找出要查询的数据,而不需要遍历整个数组。
NSDictionary就像NSString和NSArray一样是不可变的对象,但NSNutableDictionary 类允许你随意添加和删除字典的元素,创建新的NSDictionary时,就提供该字典所存储的全部对象和关键字。
字面量定义:@{key,value,...}
其中,dictionaryWithObiectsAndKeys:后面的参数先是要存储的对象,然后才是关键字,而字面量的语法则是关键字在前,数值在后。关键字和数值之间以冒号分开,而每对键值之间则以逗号区分开。
1 +(id)dictionaryWithObiectsAndKeys:(id)firstObject,-; 2 //该方法接受对象和关键字交替出现的序列,以nil作为终止符号(NSDictionary中不能存储nil值,字面量语法中不需要nil值) 3 //假设我想创建一个存储汽车轮胎的字典,而轮胎使用可读的标签进行查找而不是数组中的任意索引,可以按照下面的方式创建字典 4 Tire *t1 = [Tire new]; 5 Tire *t2 = [Tire new]; 6 Tire *t3 = [Tire new]; 7 Tire *t4 = [Tire new]; 8 NSDictionary *tires = [NSDictionary dictionaryWithObjects:t1,@"front-left",t2,@"front-right",t3,@"back-left",t4,@"back-right",nil]; 9 //也可以 10 NSDictionary *tires = @(@"front-left":t1,@"front-right":t2,@"back-left":t3,@"back-right",t4); 11 //使用objectForKey:方法并传递前面用来存储的关键字,可以访问字典中的数值: 12 -(id)objectForKey:(id)aKey; 13 //或者是 14 tire *tire = [tires objectForKey:@"back-right"]; 15 //或者是 16 tire *tire = tires [@"back-right"]; 17 //假设字典中没有右后方轮胎,字典中将返回nil值
向NSMutableDictionary类发送dictionary消息,便可以创建新的NSMutableDictionary对象,也可以使用dictionaryWithCapacity: 方法来创建新的可变字典并告诉Cocoa该字典的最终大小。字典的容量仅仅是一个建议,不对其大小的限制,可以使用setObject:forKey: 方法为字典添加元素:
+(id)dictionaryWithCapacity:(NSUInteger) numItems; //添加字典元素 -(void)dictionaryWithCapacity:(NSUInteger) numItems; // 存储轮胎的字典还有一种创建方法 NSDictionary *tires = [NSMutableDictionary dictionary]; [tires setobject:t1 forkey:@"front-left"]; [tires setobject:t2 forkey:@"front-right"]; [tires setobject:t3 forkey:@"back-left"]; [tires setobject:t3 forkey:@"back-right"]; //如果字典中已有的关键字使用setObject:forKey:方法,那这个方法将会用新值替换掉原有的数值,如果想在可变数组中删除一些关键字,可使用removeObjectForKey: 方法: -(void)removeObjectForKey:(id) aKey; //例如一个轮胎脱落,可以把这个轮胎从字典中删除 [tires removeObjectForKey:@"back-left"];
与NSArray一样没有适用于NSMutableDictionary 字面量初始化语法。
11、NSNumber
Cocoa使用NSNumber类来封装基本数据类型。可以使用以下类方法来创建新的NSNumber对象:
1 //创建新的NSNumber 2 +(NSNumber *)numberWithChar:(char) value; 3 +(NSNumber *)numberWithInt:(char) value; 4 +(NSNumber *)numberWithFloat:(char) value; 5 +(NSNumber *)numberWithBool:(char) value;
也可以使用字面量来创建这些对象:
1 //使用字面量语法来创建这些对象 2 NSNumber *number; 3 number = @'X'; //字符量 4 number = @12345; //整型 5 number = @12345ul; //无符号长整型 6 number = @12345ll; //long 7 number = @123.45f; //浮点型 8 number = @123.45; //双浮点型 9 number = @YES; //布尔值
创建完了可以放入字典或数组中:
1 //创建NSNumber后,将放入字典或数组中 2 NSNumber @number = @42; 3 [array addObject number]; 4 [dictionary setObject: number forKey:@"Bork"]; 5 //将一个基本类型数据封装到NSNumber后,可以通过下面的实例方法来重新获得它 6 -(char)charValue; 7 - (int)intvaule; 8 - (float) floatVaule; 9 - (BOOL) boolVaule; 10 - (NSString *) stringValue;
将创建方法和提取方法搭配到一起使用是完全可以的,例如:用numberWithFloat:创建的NSNumber 对象可以用intValue方法来提取数值。NSNuber会对数据进行适当的转换。
12、NSValue
NSNumber实际上是NSValue的子类,NSValue可以封装任意值。可以使用NSValue将结构体放入NSArray或NSDictionary中,使用下面的方法能创建新的NSValue对象。
1 +(NSVaule *)vauleWithBytes : (const void *)value objCTyoe:(const *)type;
传递的参数是你想要封装的数值的地址(如一个NSSize或者自己的struct),通常你得到的是想要存储的变量的地址。也可以是提供一个用来描述这个数据类型的字符串,通常用来说明struct中实体的类型和大小。
1 NSRect rect = NSMakeRect(1,2,30,40); 2 NSValue *value = [NSValue valueWithBytes:@rect objTCType:@encode(NSRect)]; 3 [array addObject:value]; 4 5 //使用getValue:来提取数值 6 -(void)getVaule:(void *)buffer; 7 8 //调用getValue:时,需要传递存储这个数值的变量地址: 9 vaule = [array objecct AtIndex: 0]; 10 [value getValue:@rect]; 11 //getValue:方法名使用get,表明我们提供的是一个指针,而指针指向的空间则用来存储该方法生成的数据
cocoa提供将常用的struct型数据转换NSValue的便捷方法。如下:
1 + (NSVaule *) valueWithPoint:(NSPoint)aPoint; 2 + (NSVaule *) valueWithSize:(NSSize)size; 3 + (NSVaule *) valueWithrRect:(NSRect)size; 4 - (NSPoint)pointVaule; 5 - (NSSize)sizeValue; 6 - (NSRect)rectValue; 7 8 //按照以下方式在NSArray中存储和提取NSRect值 9 value = [NSValue valueWithRect:rect]; 10 [array addObject:value]; 11 - 12 NSRect anotherRect = [value rectValue];
1 //创建 2 +(NSNull *) null; 3 //添加到集合 4 [contact setObject: [NSNull null] forKey:@"home fax machine"]; 5 //而访问的方式则如下 6 id homefax = [contact object ForKey:@"home fax machine"]; 7 if(homefax == [NSNull null]) 8 { 9 ...确定没有传真机后的行为 10 } 11 //[NSNull null]总是返回一样的数值,所以你可以使用运算符==将该值与其他进行比较
14、示例:查找文件
翻查你的mac电脑上的主目录以查找.jpg文件并打印到列表中。
1 //存放在main中 2 int main (int argc , const char * argv[]) 3 { 4 //自动释放池 5 @autoreleasepool 6 { 7 //NSFileManager 允许对文件系统进行操作,如创建目录、删除文字、移动文件或者获取文件信息; 8 //defaultManager类方法可以创建一个属于自己的NSFileManager; 9 NSFileManager *manager; 10 manager = [NSFileManager defaultManager]; 11 12 NSString *home; 13 //~代表主目录的路径 14 home = [@"~" stringByExpandingTildeInPath]; 15 16 //NSFileManager类创建一个NSDirectoryEnumerator对象来遍历文件的层次结构 17 NSDirectoryEnumerator *direnum; 18 direnum = [manager enumeratorAtPath:home]; 19 20 NSMutableArray *files; 21 //创建一个可变数组并将查找到的路径添加进去 22 files = [NSTableArray arrayWithCapacity:42]; 23 24 NSString *filename; 25 while ([filename =[direnum nextObject]) 26 //目录枚举器将返回一个代表文件路径的NSString字符串。 27 //当枚举器结束时返回nil值,于是终止循环。 28 { 29 // pathExtension方法能输出文件的扩展名 30 //使用嵌套的方法调用来获取路径扩展名将获得的字符串传递给 isEqualTo:方法。如果返回结果是YES,则该文件将会添加到文件数组中 31 if( [[filename pathExtension] isEqualTo: @"jpg"]) 32 { 33 [files addObject : filename]; 34 } 35 } 36 NSMutableArray *fileenum; 37 filename =[fileenum nextObject]; 38 39 //目录循环结束后,遍历文件数组,用NSLog()函数将数组内容输出。 40 while ([filename =[fileenum nextObject]) 41 { 42 NSLog(@"%@",filename); 43 } 44 } 45 return 0; 46 }//main
15、通过快速枚举的方法
可将已有的NSEnumerator对象或者其子类传递给它,而刚好NSDictionaryEnumerator是NSEnumerator的子类,将-enumeratorAtPath:方法返回的结果传递给快速枚举。
1 //存放在main中 2 int main (int argc , const char * argv[]) 3 { 4 //自动释放池 5 @autoreleasepool 6 { 7 //NSFileManager 允许对文件系统进行操作,如创建目录、删除文字、移动文件或者获取文件信息; 8 //defaultManager类方法可以创建一个属于自己的NSFileManager; 9 NSFileManager *manager; 10 manager = [NSFileManager defaultManager]; 11 12 NSString *home; 13 //~代表主目录的路径 14 home = [@"~" stringByExpandingTildeInPath]; 15 16 NSMutableArray *files; 17 //创建一个可变数组并将查找到的路径添加进去 18 files = [NSTableArray arrayWithCapacity:42]; 19 20 for (NSString @filename in [manager enumeratorAtPath:home]) 21 { 22 // pathExtension方法能输出文件的扩展名 23 //使用嵌套的方法调用来获取路径扩展名将获得的字符串传递给 isEqualTo:方法。如果返回结果是YES,则该文件将会添加到文件数组中 24 if( [[filename pathExtension] isEqualTo: @"jpg"]) 25 { 26 [files addObject : filename]; 27 } 28 } 29 for (NSString *filename in files) 30 { 31 NSLog(@"%@",filename); 32 } 33 } 34 return 0; 35 }//main
小结:
本章学习包括
1、类方法,即由类本身而不是某个示例来处理的方法;
2、@encode()指令,即用于需要描述C语言基础类型的方法:快速枚举。
3、Cocoa类,包括NSString、NSArray、NSDictionary
NSString:用来存储人可以直接看得懂的文本
NSArray和NSDictionary:用来存储对象的集合,这些对象都是不可变的,一旦生成就不能够改动,cocoa提供了这些类的可变版本,以便随意更改他们的内容。