第六章:Foundation框架详解

Foundation框架是Cocoa编程、iOS编程的基础框架,它包括字符串、集合、日期、时间等基础。
本章包括:
    NSString和NSMutableString
    代表日期、时间的NSDate
    NSCopying和NSMutableCopying
    NSArray和NSMutableArray
    NSSet和NSMutableSet和NSCountedSet
    NSOrderedSet和NSMutableOrderedSet
    NSDictionary和NSMutableDictionary

一、字符串(NSString与NSMutableString)

1、创建字符串

NSString大致功能

  • (1)、创建字符串:创建字符串既可使用init开头的实例方法,也可以使用string开头的类方法,当然也可以直接用@“”的形式给出字符串直接量;
  • (2)、读取文件或网络URL来初始化字符串;
  • (3)、将字符串内容写入文件或URL;
  • (4)、获取字符串长度,即可获取字符串包括的字符个数,也可以获取字符串包括的字节个数;
  • (5)、获取字符串中的字符或字节,既可获取指定位置的字符,也可以获取指定范围的字符;
  • (6)、获取字符串对应的C风格字符串;
  • (7)、连接字符串;
  • (8)、分隔字符串;
  • (9)、查找字符串内对象的字符和子串;
  • (10)、替换字符串;
  • (11)、比较字符串;
  • (12)、字符串大小比较;
  • (13)、对字符串中的字符进行大小写替换
//typedef unsigned short定义
unichar data[6] = {97,98,99,100,101,102};
//使用unicode数值数组初始化字符串
NSString* str1 = [[NSString alloc]initWithCharacters:data length:6];
NSLog(@"%@",str1);
char* cstr = "Hello iOS!";
//将C风格的字符串转换成NSString对象
NSString* str2 = [NSString stringWithUTF8String:cstr];
NSLog(@"%@",str2);
//将字符串写入自定文件
[str2 writeToFile:@"myFile.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];
//读取文件内容,用文件内容初始化字符串
NSString* str3 = [NSString stringWithContentsOfFile:@"myFile.txt" encoding:NSUTF8StringEncoding error:nil];
NSLog(@"%@",str3);

2、NSString的常用功能

NSString* str = @"Hello”;
NSString* str1 = @"hello";
NSString* book = @"《疯狂iOS讲义》”;

(1)、

//在str后面追加固定的字符串
//原来的字符串对象并不改变,只是将新生成的字符串重新赋给str指针变量
str = [str stringByAppendingString:@",iOS!"];
NSLog(@"%@",str);//Hello,iOS!

(2)、

//获取字符串中的字符
unichar OCChar = [str characterAtIndex:1];
NSLog(@"%C",OCChar);//e

(3)、

//获取字符串对象的C风格字符串
const char* cstr = [str UTF8String];
NSLog(@"获取的C字符串%s",cstr);//获取的C字符串Hello,iOS!

(4)、

//比较两个字符串是否相等 相等返回1(yes),不相等返回0(no)
BOOL ret = [str isEqualToString:str1];
NSLog(@"%d",ret);//0

(5)、

//比较字符串大小,compare:方法返回NSComparisonResult枚举值
//该枚举类型包含NSOrderedAscending、NSOrderedSame、NSOrderedDescending三个值
//分别代表调用compare:的字符串位于被比较字符串小、相等、大
switch ([str compare:str1]) {
    case NSOrderedAscending:
        NSLog(@"str小于str1");//str小于str1
        break;
    case NSOrderedSame:
        NSLog(@"str与str1相等");
        break;
    case NSOrderedDescending:
        NSLog(@"str大于str1");
        break;
    default:
        break;
}
//不区分大小的比较
NSComparisonResult result = [str caseInsensitiveCompare:str1];
NSLog(@"%ld",result);

(6)、

//在str后面追加带变量的字符串
str = [str stringByAppendingFormat:@"%@是一本非常不错的图书.",book];
NSLog(@"%@",str);//Hello,iOS!《疯狂iOS讲义》是一本非常不错的图书.

(7)、

//获取字符串的字符个数
NSLog(@"str的字符个数:%lu",[str length]);//str的字符个数:30

(8)、

//获取str按UTF-8字符集解码后字节数
NSLog(@"str按UTF-8字符集解码后字节数:%lu",[str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);//str按UTF-8字符集解码后字节数:62

(9)、

//获取str前10个字符组成的字符串
NSString* s1 = [str substringToIndex:10];
NSLog(@"%@",s1);//Hello,iOS!

(10)、

//获取str从第6个字符开始,与后面的字符组成的字符串
NSString* s2 = [str substringFromIndex:6];
NSLog(@"%@",s2);//iOS!《疯狂iOS讲义》是一本非常不错的图书.

(11)、

//获取str从第6个字符开始,到第15个字符组成的字符串
NSString* s3 = [str substringWithRange:NSMakeRange(6, 15)];
NSLog(@"%@",s3);//iOS!《疯狂iOS讲义》是一

(12)、

//获取iOS在str中出现的位置 从前向后遍历
NSRange pos = [str rangeOfString:@"iOS"];
NSLog(@"iOS在str出现的开始位置:%ld,长度为:%ld",pos.location,pos.length);//iOS在str出现的开始位置:6,长度为:3
//获取iOS在str中出现的位置 从后向前遍历
NSRange pos1 = [str rangeOfString:@"iOS" options:NSBackwardsSearch];
NSLog(@"iOS在str出现的结束位置:%ld,长度为:%ld",pos1.location,pos1.length);//iOS在str出现的开始位置:6,长度为:3

(13)、

//将str的所有字符转为大写
str = [str uppercaseString];
NSLog(@"%@",str);//HELLO,IOS!《疯狂IOS讲义》是一本非常不错的图书.

(14)、

//将str的所有字符转为小写
str = [str lowercaseString];
NSLog(@"%@",str);//hello,ios!《疯狂ios讲义》是一本非常不错的图书.

(15)、

//前缀
BOOL ret1 = [str hasPrefix:@"He"];
NSLog(@"%d",ret1);
//后缀
BOOL ret2 = [str hasSuffix:@"."];
NSLog(@"%d",ret2);

3、可变字符串(NSMutableString)

NSString类是不可变的类,即一旦NSString对象被创建,包含在这个对象中的字符串序列是不可改变的,直至这个对象被销毁。
NSSMutableString对象则代表一个字符序列可变的字符串,而且NSMutableString是NSString的子类,NSString包含的方法,NSMutableString都可直接使用。

通过方法改变NSMutableString的字符序列:

NSString* book = @"《疯狂iOS讲义》”;

(1)、

//创建一个NSMutableString对象
NSMutableString* str = [NSMutableString stringWithString:@"Hello"];

(2)、

//追加固定字符串
//字符串所包含的字符序列本身发生改变,因此无须重新赋值
[str appendString:@",iOS!"];
NSLog(@"%@",str);//Hello,iOS!

(3)、

//追加带变量的字符串
//字符串包含的字符序列本身发生了改变,因此无需重新赋值
[str appendFormat:@"%@这是一本非常不错的图书。",book];
NSLog(@"%@",str);//Hello,iOS!《疯狂iOS讲义》这是一本非常不错的图书。

(4)、

//在指定位置插入字符串
//字符串包含的字符序列本身发生了改变,因此无需重新赋值
[str insertString:@"fkit.org" atIndex:6];
NSLog(@"%@",str);//Hello,fkit.orgiOS!《疯狂iOS讲义》这是一本非常不错的图书。

(5)、

//删除从位置6到位置18的所有字符
[str deleteCharactersInRange:NSMakeRange(6, 12)];
NSLog(@"%@",str);//Hello,《疯狂iOS讲义》这是一本非常不错的图书。

(6)、

//将从位置6到位置15的字符串替换成Objective-C
[str replaceCharactersInRange:NSMakeRange(6, 9) withString:@"Objective-C"];
NSLog(@"%@",str);//Hello,Objective-C这是一本非常不错的图书。

二、日期与时间

OC为处理日期、时间提供了NSDate、NSCalendar对象,还提供了日期格式器来处理日期与字符串之间的转换。

1、日期与时间(NSDate)

(1)、

//获取代表当前日期、时间的NSDate
NSDate* date1 = [NSDate date];
NSLog(@"%@",date1);//2014-11-17 09:38:57 +0000

(2)、

//获取从当前时间开始,一天之后的日期
NSDate* date2 = [[NSDate alloc]initWithTimeInterval:3600*24 sinceDate:date1];
NSLog(@"%@",date2);//2014-11-18 09:38:57 +0000

(3)、

//获取从当前时间开始,3天之前的日期
NSDate* date3 = [[NSDate alloc]initWithTimeInterval:-3*3600*24 sinceDate:date1];
NSLog(@"%@",date3);//2014-11-14 09:38:57 +0000

(4)、

//获取从1970年1月1日开始,20年后的日期
NSDate* date4 = [[NSDate alloc]initWithTimeIntervalSince1970:3600*24*366*20];
NSLog(@"%@",date4);//1990-01-16 00:00:00 +0000

(5)、

//获取系统当前的Locale
NSLocale* locale = [NSLocale currentLocale];

(6)、

//获取NSDate在当前Locale下对象的字符串
NSString* str = [date1 descriptionWithLocale:locale];
NSLog(@"%@",str);//2014年11月17日 星期一 中国标准时间17:38:57

(7)、

//比较日期
BOOL same = [date1 isEqualToDate:date2];
NSLog(@"%d",same);//0

(8)、

//获取两个日期之间较早的日期
NSDate* earlier = [date1 earlierDate:date2];
NSLog(@"%@",earlier);//2014-11-17 09:38:57 +0000

(9)、

//获取两个日期之间较晚的日期
NSDate* later = [date1 laterDate:date2];
NSLog(@"%@",later);//2014-11-18 09:38:57 +0000

(10)、

//比较两个日期,compare:方法返回NSComparisonResult枚举值
//该枚举类型包含NSOrderedAscending、NSOrderedSame、NSOrderedDescending三个值
//分别代表调用compare:的日期位于被比较日期之前、相同、之后
switch ([date1 compare:date3]) {
    case NSOrderedAscending:
        NSLog(@"date1位于date3之前");
        break;
    case NSOrderedSame:
        NSLog(@"date1与date3日期相同");
        break;
    case NSOrderedDescending:
        NSLog(@"date1位于date3日期之后");//date1位于date3日期之后
        break;
    default:
        break;
}

(11)、

//获取两个时间之间的时间差(typedef double)NSTimeInterval
NSTimeInterval time1 = [date1 timeIntervalSinceDate:date3];
NSLog(@"date1与date3之间时间差%g秒",time1);//date1与date3之间时间差259200秒

(12)、

//获取指定时间与现在时间差
NSTimeInterval time2 = [date2 timeIntervalSinceNow];
NSLog(@"date2与现在的时间差%g秒",time2);//date2与现在的时间差86400秒

(13)、

//获取距当前时间10秒后的时间
NSDate* date = [[NSDate date] dateByAddingTimeInterval:10];

2、日期格式器(NSDateFormatter)

NSDateFormatter代表一个日期格式器,它的功能就是完成NSDate与NSString之间的转换。

使用NSDateFormatter完成NSDate与NSString之间转换的步骤如下:

  1. 创建一个NSDateFormatter对象;
  2. 调用NSDateFormatter的setDateStyle:、setTimeStyle:方法设置格式化日期、时间的风格,其中,日期、时间风格支持如下几个枚举值:

    • ①、NSDateFormatterNoStyle:不显日期、时间的风格;
    • ②、NSDateFormatterShortStyle:显示“短”的日期、时间风格;
    • ③、NSDateFormatterMediumStyle:显示“中等”的日期、时间风格;
    • ④、NSDateFormatterLongStyle:显示“长”的日期、时间风格;
    • ⑤、NSDateFormatterFullStyle:显示“完整”的日期、时间风格。

      注意:如果打算使用自己的格式模板,调用NSDateFormatter的setDateFormate:方法设置日期、时间的模板。
      
  3. 如果需要将NSDate转换成NSString,调用NSDateFormatter的stringFromDate:方法执行格式化即可;如果需要将NSString转换成NSDate,调用NSDateFormatter的dateFromString:方法执行格式化即可。

NSDate* dt = [NSDate date];

(1)、

//创建两个NSLocale,分别代表中国、美国
NSLocale* locales[] = {[[NSLocale alloc]initWithLocaleIdentifier:@"zh_CN"],[[NSLocale alloc]initWithLocaleIdentifier:@"en_US"]};

(2)、

NSDateFormatter* df[8];
//为上面的两个NSLocale创建8个NSDateFormatter对象
for(int i = 0;i < 2;i++){
    //一组
    df[i * 4] = [[NSDateFormatter alloc]init];
    //设置NSDateFormatter的日期、时间风格
    [df[i * 4] setDateStyle:NSDateFormatterShortStyle];
    [df[i * 4] setTimeStyle:NSDateFormatterShortStyle];
    //设置NSDateFormatter的NSLocale
    [df[i * 4] setLocale:locales[i]];
    //二组
    [df[i * 4 + 1] = [NSDateFormatter alloc]init];
    //设置NSDateFormatter的日期、时间风格
    [df[i * 4 + 1] setDateStyle:NSDateFormatterMediumStyle];
    [df[i * 4 + 1] setTimeStyle:NSDateFormatterMediumStyle];
    //设置NSDateFormatter的NSLocale
    [df[i * 4 + 1] setLocale:locales[i]];
    //三组
    [df[i * 4 + 2] = [NSDateFormatter alloc]init];
    //设置NSDateFormatter的日期、时间风格
    [df[i * 4 + 2] setDateStyle:NSDateFormatterLongStyle];
    [df[i * 4 + 2] setTimeStyle:NSDateFormatterLongStyle];
    //设置NSDateFormatter的NSLocale
    [df[i * 4 + 2] setLocale:locales[i]];
    //四组
    [df[i * 4 + 3] = [NSDateFormatter alloc]init];
    //设置NSDateFormatter的日期、时间风格
    [df[i * 4 + 3] setDateStyle:NSDateFormatterFullStyle];
    [df[i * 4 + 3] setTimeStyle:NSDateFormatterFullStyle];
    //设置NSDateFormatter的NSLocale
    [df[i * 4 + 3] setLocale:locales[i]];
}
for (int i = 0; i < 2; i ++) {
    switch (i) {
        case 0:
            NSLog(@"------中国日期格式------");
            break;
        case 1:
            NSLog(@"------美国日期格式------");
            break;
        default:
            break;
    }
    NSLog(@"SHORT格式的日期格式:%@",[df[i * 4] stringFromDate:dt]);
    NSLog(@"MEDIUM格式的日期格式:%@",[df[i * 4 + 1] stringFromDate:dt]);
    NSLog(@"LONG格式的日期格式:%@",[df[i * 4 + 2] stringFromDate:dt]);
    NSLog(@"FULL格式的日期格式:%@",[df[i * 4 + 3] stringFromDate:dt]);
    /*输出
     ------中国日期格式------
     SHORT格式的日期格式:14-11-17 下午6:32
     MEDIUM格式的日期格式:2014年11月17日 下午6:32:42
     LONG格式的日期格式:2014年11月17日 GMT+8下午6:32:42
     FULL格式的日期格式:2014年11月17日 星期一 中国标准时间下午6:32:42
     ------美国日期格式------
     SHORT格式的日期格式:11/17/14, 6:32 PM
     MEDIUM格式的日期格式:Nov 17, 2014, 6:32:42 PM
     LONG格式的日期格式:November 17, 2014 at 6:32:42 PM GMT+8
     FULL格式的日期格式:Monday, November 17, 2014 at 6:32:42 PM China Standard Time
     */
}

(3)、

//设置自定义格式器模板
NSDateFormatter* df2 = [[NSDateFormatter alloc]init];
[df2 setDateFormat:@"公元yyyy年MM月dd日HH时mm分ss秒"];
NSLog(@"%@",[df2 stringFromDate:dt]);//公元2014年11月17日18时27分51秒

(4)、

//根据日期字符串的格式设置格式化模板
NSDateFormatter* df3 = [[NSDateFormatter alloc]init];
NSString* dateStr = @"2013-03-02";
[df3 setDateFormat:@"yyyy-MM-dd"];
//将字符串转换为NSDate对象
NSDate* dt2 = [df3 dateFromString:dateStr];
NSLog(@"%@",dt2);//2013-03-01 16:00:00 +0000

3、日历(NSCalendar)与日期组件 (NSDateComponents)

将NSDate对象的各个字段数据分开或者将字段数据组合成NSData
NSCalendar对象包含如下两个方法:

  • (1)、(NSDateComponents*)components:fromDate:从NSData提取年、月、日、时、分、秒各时间字段的信息
  • (2)、dateFromComponents:(NSDateComponents*)comps:使用comps对象包含的年、月、日、时、分、秒各时间字段的信息。该对象非常简单,它包含了对year、month、date、day、hour、minute、second、week、weekday等各字段的数值的setter和getter方法。

从NSDate对象中分开获取个时间字段的数值的步骤如下:

  1. 创建NSCalendar对象;
  2. 调用NSCalendar的components:fromDate:方法获取NSDate对象中各时间字段的数值,该方法返回一个NSDateComponents对象;
  3. 调用NSDateComponents对象的getter方法来获取各时间字段的数值;

使用各时间字段的数值来初始化NSDate对象的步骤如下:

  1. 创建NSCalendar对象;
  2. 创建一个NSDateComponents对象,调用对象的setter方法来设置各时间字段的值;
  3. 调用NSCalendar的dateFromComponents:(NSDateComponents*)初始化NSDate对象,该方法返回一个NSDate对象。

例如:

//获取代表公历的NSCalendar对象
NSCalendar* calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
//获取当年日期
NSDate* dt = [[NSDate alloc]init];
//定义一个时间字段的旗标,指定将会获取指定年、月、日、时、分、秒的信息
unsigned unitFlags = NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit|NSWeekdayCalendarUnit;
//获取不同时间字段的信息
NSDateComponents* comp = [calendar components:unitFlags fromDate:dt];
//获取不同时间字段的数值
NSLog(@"现在是%ld年",comp.year);//现在是2014年
NSLog(@"现在是%ld月",comp.month);//现在是11月
NSLog(@"现在是%ld日",comp.day);//现在是17日
NSLog(@"现在是%ld时",comp.hour);//现在是21时
NSLog(@"现在是%ld分",comp.minute);//现在是59分
NSLog(@"现在是%ld秒",comp.second);//现在是11秒
NSLog(@"现在是星期%ld",comp.weekday);//现在是星期2
//再次创建一个NSDateComponents对象
NSDateComponents* comp2 = [[NSDateComponents alloc]init];
//设置各时间字段的数值
comp2.year = 2014;
comp2.month = 11;
comp2.day = 5;
comp2.hour = 18;
comp2.minute = 34;
//通过NSDateComponents所包含的时间字段的数值来恢复NSDate对象
NSDate* date = [calendar dateFromComponents:comp2];
NSLog(@"%@",date);//2014-11-05 10:34:00 +0000

4、定时器(NSTimer)

如果程序需要让某个方法重复执行,可借助OC的定时器来完成,具体步骤如下:

  • 调用NSTimer的scheduledTimerWithTimeInterval:invocation:repeats:或
    scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:类方法来创建NSTimer对象。调用该类方法时,如要传入如下参数:
    • ①、timeInterval:指定每隔多少秒执行一次任务;
    • ②、invocation或target与selector:指定重复执行任务。如果指定target和selector参数,则指定用某个对象的特定方法作为重复执行的任务;如果指定invocation参数,该参数需要传入一个NSInvocation对象,其中NSInvocation对象也是封装target和selector的,其实也是指定用某个对象的特定方法作为重复执行的任务;
    • ③、userInfo:该参数用于传入额外的附加信息;
    • ④、销毁定时器。调用定时器的invalidate方法即可。

例如:

//定义定时器①
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(info:) userInfo:nil repeats:YES];
//定义定时器②
NSTimer* timer2 = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(info:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:timer2 forMode:NSDefaultRunLoopMode];
//定义定时器③
NSTimer* timers = [[NSTimer alloc]initWithFireDate:[NSDate distantPast] interval:0.5 target:self selector:@selector(info:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:timers forMode:NSDefaultRunLoopMode];
//开启定时器
[timer2 setFireDate:[NSDate distantPast]];
//关闭定时器
[timer2 setFireDate:[NSDate distantFuture]];
count = 0;
//执行方法
- (void)info:(NSTimer *)timer{
    NSLog(@"正在执行第%d次任务",count++);
    //如果count的值大于10,取消定时器
    if (count > 10) {
        NSLog(@"取消执行定时器");
        [timer invalidate];//取消定时器
    }
}

5、时区(NSTimeZone)

基本概念:

  • ①、GMT 0:00 格林威治标准时间; UTC +00:00 校准的全球时间; CCD +08:00 中国标准时间 [来自百度百科]
  • ②、夏时制,英文”DaylightSavingTime”。夏季时将时区内的时间提前(一般为1小时),以节省资源,提高效率。使用夏时制期间,当前时区相对于GMT的时间偏移量会发生变化。在某些应用中可能需要考虑。
  • ③、任何时区都以GMT为基准,即,任何NSTimeZone对象所代表的时区都是相对于GMT的,这里的相对性是NSTimeZone中最重要的属性,我们称之为当前时区相对于GMT的偏移量。一旦知道了一个偏移量,便可以确定一个时区。在iOS中,偏移量是以”秒”为单位的。
  • ④、NSTimeZone是一个类簇,我们所使用的任何NSTimeZone对象都是NSTimeZone的私有子类。
  • ⑤、iOS中的时间类NSDate中存储的时间,都是相对于GMT的,我们使用NSDate时,会根据App的时区设置返回与时区对应的数据。
  • ⑥、iOS系统中的/usr/share/zoneinfo/目录中保存了所有的可根据 地理位置名称 或 时区别名 得到的时区信息。时区别名都是与具体的地理位置一一对应的。(已越狱的童鞋请看)
  • ⑦、iOS中的时区表示方法:GMT+0800 GMT-0800。(+:东区 -:西区 08:小时数 00:分钟数)。 GMT+0830就是指比GMT早8小时外加30分钟的时区。

(1)、

//系统时区
NSTimeZone *zone = [NSTimeZone systemTimeZone];
NSString* name = [zone name];//Africa/Abidjan

(2)、

//当地时区
NSTimeZone *localTime = [NSTimeZone localTimeZone];

(3)、

NSDate *date = [NSDate date];
//和格林尼治时间差
NSInteger timeOff = [zone secondsFromGMT];
//视察转化
NSDate *timeOffDate = [date dateByAddingTimeInterval:timeOff];
NSLog(@"timeOffDate:%@",timeOffDate);//timeOffDate:2015-03-19 11:16:16 +0000

(4)、

//取得目前已知的所有地里名称
NSArray *timeZoneNames = [NSTimeZone knownTimeZoneNames];
for(NSString *name in timeZoneNames) {
    NSTimeZone *timezone = [[NSTimeZone alloc] initWithName:name];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    //设定时间格式
    [formatter setDateFormat:@"YYYY-MM-d HH:mm:ss"];
    //设定时区
    [formatter setTimeZone:timezone];
    //时间格式正规化并做时区校正
    NSString *correctDate = [formatter stringFromDate:date];
    NSLog(@"地点:%@ 当地时间:%@",[timezone name], correctDate);//地点:Africa/Asmara 当地时间:2015-03-19 06:11:04
}

6、本地化(NSLocale)

本地化封装了关于语言,文化以及技术约定和规范的信息。用于提供于用户所处地域相关的定制化信息和首选项信息的设置。通过获取用户的本地化信息设置,我们可以为用户提供更加友好人性化的界面设置,包括更改应用程序的界面的语言,货币类型,数字,日期格式的格式化,提供正确的地理位置显示等等。IOS内置为应用程序的开发提供了很好的本地化机制,良好的本地化意味着应用程序可以为更多的用户提供服务。其中NSLocale类的的主要作用便是用来封装本地化相关的各种信息,下面简单列举下NSLocale的一些方法,但NSLocale更多是使用在对数字,时间日期本地化的处理的过程。

(1)、

// 根据本地标识符创建本地化对象——中国
NSLocale* locale = [[NSLocale alloc]initWithLocaleIdentifier:@"zh_CN"];

(2)、

// 获取系统所有本地化标识符数组列表
NSArray* array = [NSLocale availableLocaleIdentifiers];
// 获取所有已知合法的国家代码数组列表
NSArray* array2 = [NSLocale ISOCountryCodes] ;
// 获取所有已知合法的ISO货币代码数组列表
NSArray* array3 = [NSLocale ISOCurrencyCodes] ;
// 获取所有已知合法的ISO语言代码数组列表
NSArray* array4 = [NSLocale ISOLanguageCodes] ;

(3)、

//获取本地化对象的具体内容
NSLocale* currentLocale = [NSLocale currentLocale];
NSLog(@"%@--%@",[currentLocale objectForKey:NSLocaleIdentifier],[currentLocale objectForKey: NSLocaleLanguageCode]);//en_US—en
NSString* strLanguage = [[[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"] objectAtIndex:0];
NSLog(@"%@",strLanguage);//en

注意:key值参见NSLocale Calendar Keys

(4)、

//获取当前系统设置语言的标识符
NSString* currentString = [[NSLocale currentLocale] localeIdentifier];
NSLog(@"%@",currentString);//en_US
NSString* currentString1 = [[NSLocale currentLocale] objectForKey:NSLocaleIdentifier];
NSLog(@"%@",currentString1);//en_US

(5)、

//获取当前语言的排版方向和字符方向
//返回类型为NSLocaleLanguageDirection枚举
[NSLocale lineDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]];
[NSLocale characterDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]];

三、对象复制

1、copy和mutableCopy方法

  • (1)、copy方法用于复制对象的副本。copy方法总是返回对象的不可修改的副本,即使该对象本身是可修改的。
  • (2)、mutableCopy方法用于复制对象的可变副本。mutableCopy方法总是返回该对象可修改的副本,即使被复制的对象本身是不可修改的。调用mutableCopy方法复制出来的副本也是可修改的。

    另外:copy和mutableCopy返回的总是原对象的副本,当程序对复制的副本进行修改时,原对象通常不会受到影响。
    
NSMutableString* book = [NSMutableString stringWithFormat:@"疯狂iOS讲义"];
//复制book字符串的可变副本
NSMutableString* bookCopy = [book mutableCopy];
[bookCopy replaceCharactersInRange:NSMakeRange(2, 3) withString:@"Android"];
//此处看到原字符串并没有改变
NSLog(@"book的值为:%@",book);//book的值为:疯狂iOS讲义
//字符串副本发生了改变
NSLog(@"bookCopy的值为:%@",bookCopy);//bookCopy的值为:疯狂Android讲义
NSString* str = @"fkit";
//复制str(不可变字符串)的可变副本
NSMutableString* strCopy = [str mutableCopy];
//向可变字符串后面追加字符串
[strCopy appendString:@".org"];
NSLog(@"strCopy的值为:%@",strCopy);//strCopy的值为:fkit.org
//调用book(可变字符串)的copy方法,程序返回一个不可修改的副本
NSMutableString* bookCopy2 = [book copy];
[bookCopy2 appendString:@"1111"];//bookCopy2本质为不可变所以此处系统崩溃

2、NSCopying与NSMutableCopy协议

自定义的类不能直接使用copy、mutableCopy需要重写copyWithZone:和mutableWithZone:方法来完成实际的复制工作,否则会报错:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[FKDog copyWithZone:]: unrecognized selector sent to instance 0x1001028e0'

解决:

  • (1)、让该类实现NSCopying协议;
  • (2)、让该类实现copyWithZone:方法。

或者:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[FKDog mutableCopyWithZone:]: unrecognized selector sent to instance 0x100202c80’

解决:

  • (1)、让该类实现NSMutableCopy协议;
  • (2)、让该类实现mutableCopyWithZone:方法。

例如:

FKDog的接口部分:

#import <Foundation/Foundation.h>
@interface FKDog : NSObject<NSCopying,NSMutableCopying]] >

@property (nonatomic ,strong)NSMutableString* name;
@property (nonatomic ,assign)int age;
@end
FKDog的实现部分:
#import "FKDog.h"
#import "FKMyException.h"
//为FKDog提供实现部分
@implementation FKDog
@synthesize age = _age;
@synthesize name = _name;
- (id)copyWithZone:(NSZone *)zone{
    FKDog* dog = [[[self class]allocWithZone:zone]init];
    dog.name = self.name;
    dog.age = self.age;
    return dog;
}
- (id)mutableCopyWithZone:(NSZone *)zone{
    FKDog* dog = [[FKDog alloc]init];
    dog.name = [self.name mutableCopy];
    dog.age = self.age;
    return dog;
}
@end

mian函数的实现部分

FKDog* dog1 = [FKDog new];
dog1.name = [NSMutableString stringWithFormat:@"旺财"];
dog1.age = 10;
FKDog* dog2 = [dog1 copy];
dog2.name = [NSMutableString stringWithFormat:@"snoopy"];
dog2.age = 20;
NSLog(@"dog1的名字为:%@",dog1.name);//dog1的名字为:旺财
NSLog(@"dog1的年龄为:%d",dog1.age);//dog1的年龄为:10
NSLog(@"dog2的名字为:%@",dog2.name);//dog2的名字为:snoopy
NSLog(@"dog2的年龄为:%d",dog2.age);//dog2的年龄为:20

3、浅复制与深复制

深复制(deep copy)与浅复制(shallow copy)

必须要注意:

如果写成下面:

FKDog* dog1 = [FKDog new];
dog1.name = [NSMutableString stringWithFormat:@"旺财"];
dog1.age = 10;
FKDog* dog2 = [dog1 copy];
[dog2.name replaceCharactersInRange:NSMakeRange(0, 2) withString:@"snoopy"];
dog2.age = 20;
NSLog(@"dog1的名字为:%@",dog1.name);//dog1的名字为:snoopy
NSLog(@"dog1的年龄为:%d",dog1.age);//dog1的年龄为:10
NSLog(@"dog2的名字为:%@",dog2.name);//dog2的名字为:snoopy
NSLog(@"dog2的年龄为:%d",dog2.age);//dog2的年龄为:20

解释:dog是复制出来的对象,此时程序将被复制对象的name赋值给dag的name,注意,name只是一个指针变量,该变量中存放的只是字符串的地址,并不是字符串本身,这样赋值的效果是让dog的name与被复制对象name属性指向同一个字符串,当程序改变任何一个FKDog的name实例变量时,另一个FKDog对象的name属性值也会随着改变。

  • 浅复制:当对象的实例变量是指针变量时,如果程序只是复制该指针的地址,而不是真正复制指针所指向的对象。
  • 深复制:深复制不仅会复制对象本身,而且会递归复制每个指针类型的实例变量,直到两个对象没有任何公用的地方。

4、setter方法的复制选项

@property (nonatomic ,copy)NSMutableString* name;

copy方法默认是复制该对象的不可变副本,虽然程序传入的NSMutableString,但程序调用该参数的copy方法得到的是不可变副本。

四、Objective-C集合概述

Objective-C集合大致上分为:NSArray、NSSet、NSDictionary三种体系;

  • NSArray:代表有序、可重复的集合;
  • NSSet:代表无序,不可重复的集合;
  • NSDictionary:代表具有映射关系的集合。

(1)、集合类:只能保存对象(实际上是保存对象的指针变量,但通常认为集合里保存的是对象);
(2)、数组:可以保存基本类型的值,也可以保存对象。

五、数组(NSArray与NSMutableArray)

NSArray代表元素是有序、可重复的一个集合,集合中每个元素都有其对象的顺序索引。NSArray集合允许使用重复元素,可以通过索引来访问指定位置的集合元素。

提示:NSArray只是保存对象的指针,因此NSArray只保证这些指针变量中的地址不能改变,但指针变量所指向的对象是可以改变的.

1、NSArray的功能与用法

  • (1)、初始化数组(类方法以array开始,实例方法以init开头)
    • ①、array:创建一个不包含任何元素的空NSArray;
    • ②、arrayWithContentsOfFile:/initWithContentsOfFile:读取文件内容来创建NSArray;
    • ③、arrayWithObject:创建只包含指定元素的NSArray;
    • ④、arrayWithObjects:/initWithObjects:创建包含指定的N个元素的NSArray;
  • (2)、NSArray集合的方法:
    • ①、查询几个元素在NSArray中的索引;
    • ②、根据索引值取出NSArray集合中的元素;
    • ③、对集合元素整体调用方法;
    • ④、对NSArray集合进行排序;
    • ⑤、取出NSArray集合中部分集合组成新集合。

例如:
(1)、

NSArray* array = [NSArray arrayWithObjects:@"疯狂iOS讲义",@"疯狂Android讲义",@"疯狂Ajax讲义",@"疯狂XML讲义",@"Struts 2.x权威指南", nil];
NSLog(@"第一个元素:%@",[array objectAtIndex:0]);//第一个元素:疯狂iOS讲义
NSLog(@"索引为1的元素:%@",[array objectAtIndex:1]);//索引为1的元素:疯狂Android讲义
NSLog(@"最后一个元素:%@",[array lastObject]);//最后一个元素:Struts 2.x权威指南

(2)、

//获取索引从2~5的元素组成的新集合
NSArray* arr1 = [array objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 3)]];
NSLog(@"arr1 = %@",arr1);
/*
 输出
 arr1 = (
 "\U75af\U72c2Ajax\U8bb2\U4e49",
 "\U75af\U72c2XML\U8bb2\U4e49",
 "Struts 2.x\U6743\U5a01\U6307\U5357"
 )
 */

(3)、

//获取元素在集合中的位置
NSLog(@"疯狂Android讲义的位置:%ld",[array indexOfObject:@"疯狂Android讲义"]);//疯狂Android讲义的位置:1

(4)、

//获取元素在集合指定范围中的位置
NSLog(@"疯狂Android讲义在指定范围中的位置:%ld",[array indexOfObject:@"疯狂Android讲义" inRange:NSMakeRange(2, 3)]);//疯狂Android讲义在指定范围中的位置:9223372036854775807  因为没有所以返回该数据

(5)、

//向数组的最后最佳一个元素
//原array本身并没有改变,只是将新返回的NSArray赋给array
array = [array arrayByAddingObject:@"孙悟空"];

(6)、

//向array数组的最后追加另一个数组中的所有元素
//原NSArray本身并没有改变,只是将新返回的NSArray赋给array
array = [array arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:@"宝玉",@"黛玉", nil]];

(7)、

//遍历数组
for (int i = 0; i < array.count; i ++) {
    NSLog(@"%@",[array objectAtIndex:i]);
}
for (NSString* str in array) {
    NSLog(@"%@",str);
}

(8)、

//获取数组中索引为5~8的所有元素
NSArray* arr2 = [array subarrayWithRange:NSMakeRange(5, 3)];
NSLog(@"arr2 = %@",arr2);

(9)、

//将NSArray集合的元素写入文件
[arr2 writeToFile:@"myFile.txt" atomically:YES];

(10)、

//将字符串以指定字符串分割成不可变数组
NSString* str1 = @"12345432123454321";
NSString* str2 = @"2";
NSArray* arr3 = [str1 componentsSeparatedByString:str2];
NSLog(@"arr3 = %@",arr3);
/*
 输出
 arr3 = (
 1,
 34543,
 1,
 34543,
 1
 )
 */

(11)、

//按照字符串中的各字符串进行分割成不可变数组,不会改变原来字符串的内容
NSString* str1 = @"12345432123454321";
NSString* str2 = @"25";
NSArray* arr4 = [str1 componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:str2]];
NSLog(@"arr4 = %@",arr4);
/*
 输出
 arr4 = (
 1,
 34,
 43,
 1,
 34,
 43,
 1
 )
 */

注意:NSIndexSet集合与NSSet集合的功能基本相似,区别只是NSIndexSet集合主要用于保存索引值,因此,他的集合元素都是NSUInteger对象。

2、对集合元素整体调用方法

NSArray允许对结合中所有的元素或部分元素整体调用方法,如果只是简单地调用集合元素的方法,可通过如下两种方法:

  • (1)、makeObjectsPerformSelector:依次调用NSArray集合中每个元素的指定方法,该方法需要传入一个SEL参数,用于指定调用哪种方法。
  • (2)、makeObjectsPerformSelector:withObject:依次调用NSArray集合中每个元素的指定方法,该方法第一个SEL参数用于指定调用哪个方法,第二个参数用于调用集合元素的方法时传入参数;第三个参数用于控制是否终止迭代,如果在处理某个元素后,将第三个元素赋为YES,该方法就会终止迭代调用。

如果希望对集合中多有元素进行隐式遍历,并使用集合元素来执行某一段代码,则可通过NSArray的如下方法来完成

  • (1)、enumerateObjectsUsingBlock:遍历集合中的所有元素,并依次使用元素来执行指定的代码块;
  • (2)、enumerateObjectsWithOptions:usingBlock:遍历集合中所有的元素,并依次使用元素来执行指定的代码块。该方法可以额外传入一个参数,用于控制遍历的选项,如反向遍历。
  • (3)、enumerateObjectsAtIndexes:options:usingBlock:遍历集合中指定范围内的元素,并依次使用元素来执行指定的代码块。该方法可传入一个选项参数,用于控制遍历的选项,如反向遍历。

注意:上面3个方法都需要传入一个代码块参数,该代码块必须带3个参数,前一个参数代表在遍历的集合元素,第二个参数代表正在遍历的集合元素的索引。

例如:

FKUser.m的实现部分

#import "FKUser.h"
@implementation FKUser
@synthesize name;
@synthesize pass;
- (id)initWithName:(NSString *)aName pass:(NSString *)aPass{
    if (self = [super init]) {
        name = aName;
        pass = aPass;
    }
    return self;
}
- (void)say:(NSString *)content{
    NSLog(@"%@说:%@",self.name,content);
}
- (NSString *)description{
    return [NSString stringWithFormat:@"<FKUser[name=%@,pass=%@]>",self.name,self.pass];
}
main中的实现部分
//初始化NSArray对象
NSArray* array = [NSArray arrayWithObjects:[[FKUser alloc]initWithName:@"sun" pass:@"123"],[[FKUser alloc]initWithName:@"bai" pass:@"345"], [[FKUser alloc]initWithName:@"zhu" pass:@"654"],[[FKUser alloc]initWithName:@"tang" pass:@"178"],[[FKUser alloc]initWithName:@"niu" pass:@"155"],nil];
//对集合元素整体调用方法
[array makeObjectsPerformSelector:@selector(say:) withObject:@"下午好,NSArray真强大"];
/*
 输出:
 sun说:下午好,NSArray真强大
 bai说:下午好,NSArray真强大
 zhu说:下午好,NSArray真强大
 tang说:下午好,NSArray真强大
 niu说:下午好,NSArray真强大
 */
NSString* content = @"疯狂iOS讲义";
//迭代集合内指定范围内的元素,并使用该元素来执行代码块
//代码块的第一个参数代表正在遍历的集合元素
//代码块的第二个参数代表正在遍历的集合元素的索引
//options代表是正向遍历还是反向遍历
[array enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 2)] options:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    NSLog(@"正在处理第%ld个元素:%@",idx,obj);
    [obj say:content];
    /*
     输出:
     正在处理第2个元素:<FKUser: 0x100109ce0>
     zhu说:疯狂iOS讲义
     正在处理第3个元素:<FKUser: 0x100103380>
     tang说:疯狂iOS讲义
     */
}];

3、对NSArray进行排序

NSArray提供了大量的方法对集合元素进行排序,这些排序方法都以sort开头,最常用的排序方法如下:

  • (1)、sortedArrayUsingFunction:context:该方法使用排序函数对集合元素进行排序,该排序函数必须返回NSOrderedAscending、NSOrderedDescending、NSOrderedSame这些枚举值,用于代表集合元素的大小。该方法返回一个排好序的NSArray对象。
  • (2)、sortedArrayUsingSelector:该方法使用集合元素自身的方法对集合元素进行排序,集合元素的改方法必须返回NSOrderedAscending、NSOrderedDescending、NSOrderedSame这些枚举值,用于代表集合元素的大小。该方法返回一个排好序的新NSArray对象.
  • (3)、sortedArrayUsingComparator:该方法使用代码块对集合元素进行排序,该代码块必须返回NSOrderedAscending、NSOrderedDescending、NSOrderedSame这些枚举值,用于代表集合元素的大小。该方法返回一个排好序的NSArray对象。

例如:

NSInteger intSort(id num1,id num2,void *content){
    int v1 = [num1 intValue];
    int v2 = [num2 intValue];
    if (v1 < v2) {
        //升序
        return NSOrderedAscending;
    }else if(v1 > v2){
        //降序
        return NSOrderedDescending;
    }else{
        return NSOrderedSame;
    }
}

①:

//初始化一个元素为NSString的NSArray对象
NSArray* array1 = [NSArray arrayWithObjects:@"Objective-C",@"C",@"C++",@"Ruby",@"Perl",@"Python", nil];
//使用集合元素的compare:方法进行比较
array1 = [array1 sortedArrayUsingSelector:@selector(compare:)];
NSLog(@"%@",array1);
/*
 输出:
 (
 C,
 "C++",
 "Objective-C",
 Perl,
 Python,
 Ruby
 )
 */

②:

//初始化一个元素为NSNumber的NSArray对象
NSArray* array2 = [NSArray arrayWithObjects:[NSNumber numberWithInt:20], [NSNumber numberWithInt:12],[NSNumber numberWithInt:-8],[NSNumber numberWithInt:50],[NSNumber numberWithInt:19],nil];
//使用intSort函数进行排序
array2 = [array2 sortedArrayUsingFunction:intSort context:nil];
NSLog(@"%@",array2);
/*
 输出:
 (
 "-8",
 12,
 19,
 20,
 50
 )
 */

③:

//使用intSort函数进行排序
NSArray* array3 = [array2 sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    //改代码块就是根据集合元素的intValue进行比较
    if ([obj1 intValue] > [obj2 intValue]) {
        return NSOrderedDescending;
    }else if([obj1 intValue] < [obj2 intValue]){
        return NSOrderedAscending;
    }else{
        return NSOrderedSame;
    }
}];
NSLog(@"%@",array3);
/*
 输出:
 (
 "-8",
 12,
 19,
 20,
 50
 )
 */

4、使用枚举器遍历NSArray集合元素

对于NSArray对象,除了可根据集合元素的索引来遍历集合元素之外,还可以调用NSArray对象的如下两个方法来返回枚举器:

  • (1)、objectEnumerator返回NSArray集合的顺序枚举器;
  • (2)、reverseObjectEnumerator返回NSArray的集合的逆序枚举器。

上面两个方法都返回一个NSEnumerator枚举器,该枚举器只包含如下两个方法。

  • (1)、allObject:获取枚举集合中的所有元素;
  • (2)、nextObject:获取被枚举集合中的下一个元素。

注意:一般来说借助nextObject方法即可对集合元素进行枚举:程序可采用循环不短获取nextObject方法的返回值,直到该方法的返回值为nil结束循环

例如:

NSArray* array = [NSArray arrayWithObjects:[NSNumber numberWithInt:20], [NSNumber numberWithInt:12],[NSNumber numberWithInt:-8],[NSNumber numberWithInt:50],[NSNumber numberWithInt:19],nil];
//获取NSArray的顺序枚举器
NSEnumerator* en = [array objectEnumerator];
id object;
while (object = [en nextObject]) {
    NSLog(@"%@",object);
}
/*
 输出:20 12 -8 50 19
 */
NSLog(@"----下面逆序遍历----");
//获取NSArray的逆序枚举器
en = [array reverseObjectEnumerator];
while (object = [en nextObject]) {
    NSLog(@"%@",object);
}
/*
 输出:19 50 -8 12 20
 */

5、快熟枚举(for in)

Objective-C还提供一种快速枚举的方法来遍历集合(包括NSArray、NSSet、NSDictionary等集合),使用快速枚举遍历集合元素时,无须获取集合的长度,也无须根据索引来访问集合元素,即可快速枚举自动遍历集合的每个元素。

提示:如果使用快速枚举来遍历NSDictionary对象,快速枚举中循环计数器一次代表NSDictionary的每个key的值。

例如:

NSArray* array = [NSArray arrayWithObjects:[NSNumber numberWithInt:20], [NSNumber numberWithInt:12],[NSNumber numberWithInt:-8],[NSNumber numberWithInt:50],[NSNumber numberWithInt:19],nil];
for (id object in array) {
    NSLog(@"%@",object);//20 12 -8 50 19
}

6、可变数组(NSMutableArray)

方法:

  • (1)、添加集合元素的方法:这类方法以add开头;
  • (2)、删除集合元素的方法:这类方法以remove开头;
  • (3)、替换集合元素的方法:这类方法以replace开头;
  • (4)、对集合本身排序的方法:这类方法以sort开头。

例如:

NSString* NSCollectionToString(NSArray* array){
    NSMutableString* result = [NSMutableString stringWithString:@"["];
    for (id obj in array) {
        [result appendString:[obj description]];
        [result appendString:@", "];
    }
    NSUInteger len = [result length];//获取字符串长度
    //去掉字符串最后的两个字符
    [result deleteCharactersInRange:NSMakeRange(len - 2, 2)];
    [result appendString:@"]"];
    return result;
}
NSMutableArray* array = [NSMutableArray arrayWithContentsOfFile:@"myFile.txt"];

(1)、添加

//向集合后边添加一个元素
[array addObject:@"疯狂iOS讲义"];
NSLog(@"最后追加一个元素后:%@",NSCollectionToString(array));//最后追加一个元素后:[孙悟空, 宝玉, 黛玉, 疯狂iOS讲义]
//使用NSArray向集合尾部添加多个元素
[array addObjectsFromArray:[NSArray arrayWithObjects:@"张飞",@"关羽", nil]];
NSLog(@"最后追加两个元素后:%@",NSCollectionToString(array));//最后追加两个元素后:[孙悟空, 宝玉, 黛玉, 疯狂iOS讲义, 张飞, 关羽]

(2)、插入

//向集合的指定位置插入一个元素
[array insertObject:@"疯狂Ajax讲义" atIndex:2];
NSLog(@"在索引为2出插入一个元素后:%@",NSCollectionToString(array));//在索引为2出插入一个元素后:[孙悟空, 宝玉, 疯狂Ajax讲义, 黛玉, 疯狂iOS讲义, 张飞, 关羽]
//使用NSArray向集合指定位置插入多个元素
[array insertObjects:[NSArray arrayWithObjects:@"武松",@"林冲", nil] atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(3, 2)]];
NSLog(@"插入多个元素后:%@",NSCollectionToString(array));//插入多个元素后:[孙悟空, 宝玉, 疯狂Ajax讲义, 武松, 林冲, 黛玉, 疯狂iOS讲义, 张飞, 关羽]

(3)、删除

//删除最后一个元素
[array removeLastObject];
NSLog(@"删除最后一个元素后:%@",NSCollectionToString(array));//删除最后一个元素后:[孙悟空, 宝玉, 疯狂Ajax讲义, 武松, 林冲, 黛玉, 疯狂iOS讲义, 张飞]
//删除集合中指定索引处的元素
[array removeObjectAtIndex:5];
NSLog(@"删除集合中指定索引处元素后:%@",NSCollectionToString(array));//删除集合中指定索引处元素后:[孙悟空, 宝玉, 疯狂Ajax讲义, 武松, 林冲, 疯狂iOS讲义, 张飞]
//删除索引为2~5处的元素
[array removeObjectsInRange:NSMakeRange(2, 3)];
NSLog(@"删除索引为2~5处的元素后:%@",NSCollectionToString(array));//删除索引为2~5处的元素后:[孙悟空, 宝玉, 疯狂iOS讲义, 张飞]

(4)、替换

//替换索引为2处的元素
[array replaceObjectAtIndex:2 withObject:@"Android讲义"];
NSLog(@"替换索引为2处的元素后:%@",NSCollectionToString(array));//替换索引为2处的元素后:[孙悟空, 宝玉, Android讲义, 张飞]

7、NSArray的KVC与KVO

NSArray是一个容纳多个对象的集合,NSArray允许直接对集合中的所有元素进行整体的KVC编码,NSArray提供了如下两种方法:

  • (1)、setValue:forKey:将NSArray集合中的所有元素的指定key对应属性或实例变量设置为value;
  • (2)、valueForKey:返回该NSArray集合中所有元素的指定key组成的NSArray对象。

除此之外,NSArray还为集合中所有元素或部分元素进行KVO编程提供了如下方法:

  • (1)、addObjector:forKeyPath:content:为集合中所有的元素添加KVO监听器;
  • (2)、removeObserver:forKeyPath:为集合中的所有元素删除KVO监听器;
  • (3)、addObjector:toObjectsAtIndexes:forKeyPath:options:context:为集合中的指定索引处的元素添加KVO监听器
  • (4)、removeObserver:fromObjectsAtIndexes:forKeyPath:为集合中指定的索引处的元素产出KVO监听器。
NSString* NSCollectionToString(NSArray* array){
    NSMutableString* result = [NSMutableString stringWithString:@"["];
    for (id obj in array) {
        [result appendString:[obj description]];
        [result appendString:@", "];
    }
    NSUInteger len = [result length];//获取字符串长度
    //去掉字符串最后的两个字符
    [result deleteCharactersInRange:NSMakeRange(len - 2, 2)];
    [result appendString:@"]"];
    return result;
}
//初始化NSArray对象
NSArray* array = [NSArray arrayWithObjects:[[FKUser alloc]initWithName:@"sun" pass:@"123"],[[FKUser alloc]initWithName:@"bai" pass:@"345"], [[FKUser alloc]initWithName:@"zhu" pass:@"654"],[[FKUser alloc]initWithName:@"tang" pass:@"178"],[[FKUser alloc]initWithName:@"niu" pass:@"155"],nil];
//获取所有集合元素的name属性组成的新集合
id newArr = [array valueForKey:@"name"];
NSLog(@"%@",NSCollectionToString(newArr));//[sun, bai, zhu, tang, niu]
//对集合中的所有元素整体进行KVC编程
//将所有集合元素的name属性改为”新名字“
[array setValue:@"新名字" forKey:@"name"];
newArr = [array valueForKey:@"name"];
NSLog(@"%@",NSCollectionToString(newArr));//[新名字, 新名字, 新名字, 新名字, 新名字]

六、集合(NSSet与NSMutableSet)

NSSet集合不允许包含相同的元素,如果试图把两个相同的元素放在同一个NSSet集合中,则只会保留一个元素。

1、NSSet的功能与用法

NSSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。
NSSet和NSArray在如下方面的调用机制相似:

  • (1)、都可通过count方法获取集合元素的数量;
  • (2)、都可通过快速枚举来遍历集合元素;
  • (3)、通过objectEnumerator方法获取NSEnumerator枚举器集合元素进行遍历。用于NSSet集合本身就是无序的,因此提供反向迭代器没有意思;
  • (4)、都提供了makeObjectsPerformSelect:、makeObjectsPerformSelector:withObject:方法对集合元素整体调用某个方法,以及enumerateObjectsUsingBlock:、enumerateObjectsWithOptionsWithOptions:usingBlock对集合整体或部分元素迭代执行代码块;
  • (5)、都提供了valueForKey:和setValue:forKey:方法对集合元素整体进行KVC编程。
  • (6)、都提供了集合的所有元素和部分元素进行KVO编程方法。
    下面介绍NSSet的方法,提供了类方法和实例方法来初始化NSSet集合,其中以set开头的方法是类方法,以init开头的方法是实例方法。

常用的方法如下:

  • (1)、setByAddingObject:向集合中添加一个新元素,返回添加元素后的新集合;
  • (2)、setByAddingObjectsFromSet:使用NSSet集合向集合中添加多个新元素,返回添加元素后的新集合;
  • (3)、setByAddingObjectsFromArray:使用NSArray集合向集合中添加多个新元素,返回添加元素后的新集合;
  • (4)、allObjects返回该集合中所有元素组成的NSArray;
  • (5)、anyObject返回该集合中的某个元素。该方法返回的元素是不确定的,但该方法并不保证随机返回集合元素。
  • (6)、containsObject:判断集合是否包含指定元素;
  • (7)、member:判断集合是否包含与该参数相等的元素,如果包含,返回相等的元素;否则返回nil;
  • (8)、objectsPassingTest:需要传入一个代码块对集合元素进行过滤,满足该代码块条件的集合元素被保留下来并组成一个新的NSSet集合作为返回值;
  • (9)、objectsWithOptions:passingTest:与前一个方法的功能类似,只是可以额外的传入一个NSEnumerationOptions迭代选项参数;
  • (10)、isSubsetOfSet:判断当前NSSet集合是否为另一个集合的子集合。调用该方法需要传入另一个集合。
  • (11)、intersectsSet:判断两个集合的元素是否有相同的元素。也就是计算两个集合是否有交集。
  • (12)、isEqualToSet:判断两个集合的元素是否相等。

例如:
(1)、初始化

//用4个元素初始化NSSet集合
//故意传入两个相等的元素,NSSet集合只会保留一个元素
NSSet* set1 = [NSSet setWithObjects:@"疯狂iOS讲义",@"疯狂Android讲义",@"疯狂Ajax讲义",@"疯狂iOS讲义", nil];
//程序输出set1集合中的元素个数为3
NSLog(@"set1集合中元素个数为:%ld",[set1 count]);//set1集合中元素个数为:3
NSLog(@"set1集合:%@",NSCollectionToString(set1));//set1集合:[疯狂Android讲义, 疯狂iOS讲义, 疯狂Ajax讲义]
NSSet* set2 = [NSSet setWithObjects:@"孙悟空",@"疯狂iOS讲义",@"疯狂Android讲义",@"猪八戒", nil];
NSLog(@"set2集合:%@",NSCollectionToString(set2));//set2集合:[疯狂Android讲义, 疯狂iOS讲义, 猪八戒, 孙悟空]

(2)、添加元素

//向set1集合中添加单个元素,将添加元素后生成的新集合赋给set1
set1 = [set1 setByAddingObject:@"Struts 2.1权威指南"];
NSLog(@"添加一个元素后:%@",NSCollectionToString(set1));//添加一个元素后:[疯狂Android讲义, 疯狂iOS讲义, Struts 2.1权威指南, 疯狂Ajax讲义]
//使用NSSet集合向set1集合中添加多个元素,相当于计算两个集合的并集
NSSet* s = [set1 setByAddingObjectsFromSet:set2];
NSLog(@"set1与set2的并集:%@",NSCollectionToString(s));//set1与set2的并集:[疯狂iOS讲义, 猪八戒, 疯狂Ajax讲义, 疯狂Android讲义, 孙悟空, Struts 2.1权威指南]

(3)、判断交集

//判断两个集合是否有交集
BOOL b = [set1 intersectsSet:set2];
NSLog(@"set1与set2是否有交集:%d",b);//set1与set2是否有交集:1

(4)、判断是否是子集

//判断set2是否是set1的子集
BOOL bo = [set2 isSubsetOfSet:set1];
NSLog(@"set2是否是set1的子集:%d",bo);//set2是否是set1的子集:0

(5)、判断是否包含某个元素

//判断集合是否包含指定元素
BOOL bb = [set1 containsObject:@"疯狂Ajax讲义"];
NSLog(@"set1是否包含\"疯狂Ajax讲义\":%d",bb);//set1是否包含"疯狂Ajax讲义”:1

(6)、取出一个元素 但不确定

//下面两行代码将去除相同的元素,但取出那个元素是不确定的
NSLog(@"set1取出一个元素:%@",[set1 anyObject]);//set1取出一个元素:疯狂Android讲义
NSLog(@"set1取出一个元素:%@",[set1 anyObject]);//set1取出一个元素:疯狂Android讲义

(7)、遍历 取满足条件的集合

//使用代码块对集合元素进行过滤
NSSet* filteredSet = [set1 objectsPassingTest:^BOOL(id obj, BOOL *stop) {
    return (BOOL)([obj length] > 8);
}];
NSLog(@"set1中元素的长度大于8的集合元素有:%@",filteredSet);
/*
 set1中元素的长度大于8的集合元素有:{(
 "\U75af\U72c2Android\U8bb2\U4e49",
 "Struts 2.1\U6743\U5a01\U6307\U5357"
 )}
 */

2、NSSet判断集合元素重复标准

当向NSSet集合中存入一个元素时,NSSet会调用该对象的Hash方法来得到该对象的hashCode值,然后根据HashCode值决定该对象在底层Hash表中的存储位置,如果根据hashCode计算出来该元素在底层Hash表中的存储位置已经不相同,那么系统自然将他们存在不同的位置。如果两个元素的HashCode相同,接下来就要通过isEqual:方法判断两个元素是否相等,如果有两个元素通过isEqual:方法比较返回NO,NSSet依然认为他们不相等,NSSet会把它们都存在底层hash表的同一个位置,只是将这个位置形成链;如果它们通过isEqual:比较返回YES,那么NSSet认为这两个元素相等,后面的元素添加失败。
HashSet集合判断两个元素相等的标准如下:

  • (1)、两个对象通过isEqual:方法比较返回YES;
  • (2)、两个对象hash方法返回值也相等。

例如:

FKUser.m的实现部分

- (BOOL)isEqual:(id)object{
    if (self == object) {
        return YES;
    }
    if ([object class] == [FKUser class]) {
        FKUser* target = (FKUser *)object;
        return [self.name isEqualToString:target.name]&&[self.pass isEqualToString:target.pass];
    }
    return NO;
}
- (NSUInteger)hash{
    NSLog(@"---hash---");
    NSInteger nameHash = name == nil?0:[name hash];
    NSInteger passHash = pass == nil?0:[name hash];
    return nameHash*31 + passHash;
}
main的实现部分
NSSet* set = [NSSet setWithObjects:[[FKUser alloc]initWithName:@"sun" pass:@"123"],[[FKUser alloc]initWithName:@"bai" pass:@"345"],[[FKUser alloc]initWithName:@"sun" pass:@"123"],[[FKUser alloc]initWithName:@"tang" pass:@"178"],[[FKUser alloc]initWithName:@"niu" pass:@"155"], nil];
NSLog(@"set集合元素的个数:%ld",set.count);//set集合元素的个数:4
NSLog(@"%@",NSCollectionToString(set));//[<FKUser[name=tang,pass=178]>, <FKUser[name=niu,pass=155]>, <FKUser[name=sun,pass=123]>, <FKUser[name=bai,pass=345]>]

注意:如果需要把一个对象放入NSSet中,如果重写该对象对应类的isEqual:方法,也应该重写其Hash方法,其规则是:如果两个对象通过isEqual:方法标胶返回YES时,这两个对象的Hash方法返回也应该相同。PS:此方法可能不准确。

3、NSMutableSet的功能与用法

NSMutableSet主要在NSSet基础上增加了添加元素,删除元素的方法,并增加了对集合计算交集,并集,差集的方法;

  • (1)、addObject:向集合中添加单个元素;
  • (2)、removeObject:从集合中删除单个元素;
  • (3)、removeAllObject删除集合中的所有元素;
  • (4)、addObjectsFromArray:使用NSArray数组作为参数,向NSSet集合中添加参数数组中的所有元素。
  • (5)、unionSet:计算两个NSSet集合的并集;
  • (6)、minusSet:计算两个NSSet集合的差集;
  • (7)、intersectSet:用后一个集合的元素替换已有集合中所有的元素;
  • (8)、setSet:用后一个集合的元素替换已有集合中所有的元素;

例如:
(1)、初始化

//创建一个初始容量为10的Set集合
NSMutableSet* set = [NSMutableSet setWithCapacity:10];

(2)、添加一个元素

//添加一个元素
[set addObject:@"疯狂iOS讲义"];
NSLog(@"添加1个元素后:%@",NSCollectionToString(set));

(3)、添加多个元素

//添加多个元素
[set addObjectsFromArray:[NSArray arrayWithObjects:@"疯狂Android讲义",@"疯狂Ajax讲义",@"疯狂XML讲义", nil]];
NSLog(@"使用NSArray添加3个元素后:%@",NSCollectionToString(set));//使用NSArray添加3个元素后:[疯狂iOS讲义, 疯狂Ajax讲义, 疯狂Android讲义, 疯狂XML讲义]

(4)、删除一个元素

//移除一个元素
[set removeObject:@"疯狂XML讲义"];
NSLog(@"删除一个元素后:%@",NSCollectionToString(set));//删除一个元素后:[疯狂iOS讲义, 疯狂Ajax讲义, 疯狂Android讲义]
//再次创建一个Set集合
NSSet* set2 = [NSSet setWithObjects:@"孙悟空",@"疯狂iOS讲义", nil];

(5)、计算并集

//计算两个集合的并集 直接改变set集合的元素
[set unionSet:set2];
NSLog(@"并集集合:%@",NSCollectionToString(set));//并集集合:[疯狂iOS讲义, 疯狂Ajax讲义, 疯狂Android讲义, 孙悟空]

(6)、计算差集

//计算两个集合的差集 直接改变set集合的元素
[set minusSet:set2];
NSLog(@"差集集合:%@",set);//差集集合:[疯狂Ajax讲义, 疯狂Android讲义]

(7)、计算交集

//计算两个集合的交集 直接改变set集合的元素
[set intersectSet:set2];
NSLog(@"交集集合:%@",NSCollectionToString(set));//交集集合:[]

(8)、替换所有的元素

//用set2的集合元素替换set的集合元素 直接改变set集合的元素
[set setSet:set2];
NSLog(@"赋值之后集合:%@",NSCollectionToString(set));//赋值之后集合:[疯狂iOS讲义, 孙悟空]

4、NSCountedSet的功能与用法

NSCountedSet是NSMutableSet的子类,NSCountedSet为每个元素额外维护一个添加次数的状态。当程序向NSCountedSet中添加一个元素时,如果NSCountedSet集合中不包含该元素,NSCountedSet真正接纳该元素,并将该元素的添加次数标注为1;当程序向NSCountedSet中添加一个元素时,如果NSCountedSet集合中已经包含该元素,NSCountedSet不会接纳该元素,但会将该元素的添加次数加1。当程序从NSCountedSet集合中删除元素时,NSCountedSet只是将该元素的添加次数减1,只有当该元素的添加次数变为0时,该元素才会真正从NSCountedSet集合中删除。
NSCountedSet提供了如下方法来返回某个元素的添加次数:
countForObject:获取指定元素的添加次数

例如:

NSCountedSet* set = [NSCountedSet setWithObjects:@"疯狂iOS讲义",@"疯狂Android讲义",@"疯狂Ajax讲义", nil];
[set addObject:@"疯狂iOS讲义"];
//输出集合元素
NSLog(@"%@",NSCollectionToString(set));//[疯狂iOS讲义, 疯狂Android讲义, 疯狂Ajax讲义]
//获取指定元素的添加顺序
NSLog(@"\"疯狂iOS讲义\"的添加次数为:%ld",[set countForObject:@"疯狂iOS讲义"]);//"疯狂iOS讲义"的添加次数为:3
//删除元素
[set removeObject:@"疯狂iOS讲义"];
NSLog(@"删除\"疯狂iOS讲义\"1次后的结果:%@",NSCollectionToString(set));//删除"疯狂iOS讲义"1次后的结果:[疯狂iOS讲义, 疯狂Android讲义, 疯狂Ajax讲义]
NSLog(@"删除\"疯狂iOS讲义\"1次后的添加次数为:%ld",[set countForObject:@"疯狂iOS讲义"]);//删除"疯狂iOS讲义"1次后的添加次数为:1
//删除元素
[set removeObject:@"疯狂iOS讲义"];
NSLog(@"删除\"疯狂iOS讲义\"2次后的结果:%@",NSCollectionToString(set));//删除"疯狂iOS讲义"2次后的结果:[疯狂Android讲义, 疯狂Ajax讲义]
NSLog(@"删除\"疯狂iOS讲义\"2次后的添加次数为:%ld",[set countForObject:@"疯狂iOS讲义"]);//删除"疯狂iOS讲义"2次后的添加次数为:0

七、有序集合(NSOrderedSet与NSMutableOrderedSet)

  • (1)、NSOrderedSet不允许元素重复,这与NSSet集合相同
  • (2)、NSOrderedSet可以保持元素的添加顺序,而且每个元素都有索引,可以根据索引来操作元素。这与NSArray的功能相似。
    提示:NSMutableOrderedSet是NSOrderedSet的子类,代表集合元素可变的有序集合。NSMutableOrderedSet增加了添加元素,删除元素,替换元素,集合排序,以及计算集合的交集,并集,差集等功能。

例如:

(1)、初始化

NSOrderedSet* set = [NSOrderedSet orderedSetWithObjects:[NSNumber numberWithInt:40],[NSNumber numberWithInt:12],[NSNumber numberWithInt:-9],[NSNumber numberWithInt:28],[NSNumber numberWithInt:12],[NSNumber numberWithInt:17], nil];
NSLog(@"%@",NSCollectionToString(set));//[40, 12, -9, 28, 17]

(2)、获取数据

//下面方法都是根据索引来操作集合元素
NSLog(@"set集合的第一个元素:%@",[set firstObject]);//set集合的第一个元素:40
NSLog(@"set集合的最后一个元素:%@",[set lastObject]);//set集合的最后一个元素:17

(3)、根据索引获取数据

//获取指定索引处的元素
NSLog(@"set集合中索引为2的元素:%@",[set objectAtIndex:2]);//set集合中索引为2的元素:-9

(4)、根据数据获取索引

NSLog(@"28在set集合中的索引为:%ld",[set indexOfObject:[NSNumber numberWithInt:28]]);//28在set集合中的索引为:3

(5)、遍历取出满足条件的集合

//对集合进行过滤,获取元素值大于20的集合元素的索引
NSIndexSet* indexSet1 = [set indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
    return (BOOL)([obj intValue] > 20);
}];
NSLog(@"set集合中元素值大于20的元素索引为:%@",indexSet1);//set集合中元素值大于20的元素索引为:<NSIndexSet: 0x100301610>[number of indexes: 2 (in 2 ranges), indexes: (0 3)]

八、字典(NSDictionary与NSMutableDictionary)

NSDictionary用于保存具有映射关系的数据,key和value之间存在单项的一对一关系,即通过制定的key,总能找到唯一的,确定的value

1、NSDictionary的功能与用法

NSDictionary集合的方法如下:

  • (1)、dictionary:创建一个不包含任何key-value对的NSDictionary;
  • (2)、dictionaryWithContentsOfFile:/initWithContentsOfFile:读取指定文件的内容,使用指定文件内容来初始化NSDictionary。该文件通常是由NSDictionary自己输出生成的。
  • (3)、dictionaryWithDictionary:/initWithDictionary:使用已有的NSDictionary包含的key-value对来初始化NSDictionary对象;
  • (4)、dictionaryWithObject:forKey:使用单个key-value对来创建NSDictionary对象;
  • (5)、dictionaryWithObjects:forKeys:/initWithObjects:forKeys:使用两个NSArray分别指定key、value集合,创建包含多组key-value对的NSDictionary;
  • (6)、dictionaryWithObjectsAndKeys:/initWithObjects:forKeys:调用该方法时,需要按value1、key1,value2、key2,…nil格式传入多个key-value对。

一旦得到NSDictionary对象,接下来就可以通过方法来访问该集合所包含的key或value。NSDictionary提供了如下方法:

  • (1)、count该方法返回该NSDictionary所包含的key-value对的数量;
  • (2)、allKeys该方法返回该NSDictionary所包含的全部key;
  • (3)、allKeysForObject:该方法返回指定value对应的key;
  • (4)、allValues该方法返回该NSDictionary所包含的全部value;
  • (5)、objectForKey:该方法获取该NSDictionary中指定key对应的value;
  • (6)、objectForKeyedSubscript:通过该方法的支持,允许NSDictionary通过下标来获取指定key对应的value值;
  • (7)、valueForKey:该方法获取该NSDictionary中指定key对应的value;
  • (8)、keyEnumerator该方法返回用于遍历该NSDictionary所有key的NSEnumerator对象;
  • (9)、objectEnumerator该方法返回用于遍历该NSDictionary所有value的NSEnumerator对象;
  • (10)、enumeratorKeysAndObjectsUsingBlock:使用指定的代码块来迭代该集合中所有的key-value对;
  • (11)、enumeratorKeyAndObjectsWithOptions:usingBlock:使用指定的代码块来迭代执行该集合中所有的key-value对。该方法可以传入一个额外的NSEnumerationOptions参数;
  • (12)、writeToFile:atomically:将该NSDictionary对象的数据写入指定文件。

例如:

前提:添加NSDictionary的类别

#import <Foundation/Foundation.h>
@interface NSDictionary (print)
- (void)print;
@end
#import "NSDictionary+print.h"
@implementation NSDictionary (print)
- (void)print{
    NSMutableString* result = [NSMutableString stringWithString:@"{"];
    //使用快速枚举语法来遍历NSDictionary
    //循环计数器将依次等于该NSDictionary的每个key
    for(id key in self){
        [result appendString:[key description]];
        [result appendString:@"="];
        //使用下标访问法根据key来获取对应的value
        [result appendString:[self[key] description]];
        [result appendString:@", "];
    }
    //获取字符串长度
    NSUInteger len = [result length];
    //去掉字符串最后的两个字符
    [result deleteCharactersInRange:NSMakeRange(len - 2, 2)];
    [result appendString:@"}”];
    NSLog(@"%@",result);
}

(1)、初始化

//直接使用多个value,key的形式创建NSDictionary对象
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:[[FKUser alloc]initWithName:@"sun" pass:@"123"],@"one",[[FKUser alloc]initWithName:@"bai" pass:@"345"],@"two",[[FKUser alloc]initWithName:@"sun" pass:@"123"],@"three",[[FKUser alloc]initWithName:@"tang" pass:@"178"],@"four",[[FKUser alloc]initWithName:@"niu" pass:@"155"],@"five",nil];
[dict print];

(2)、包含元素个数

NSLog(@"dict包含%ld个key-value对",[dict count]);//dict包含5个key-value对

(3)、获取全部的key

NSLog(@"dict的所有key为:%@",[dict allKeys]);
/*
 dict的所有key为:(
 one,
 five,
 three,
 two,
 four
 )
 */

(4)、获取指定元素的key

NSLog(@"<FKUser[name=sun,pass=123]对应的所有key为:%@",[dict allKeysForObject:[[FKUser alloc]initWithName:@"sun" pass:@"123"]]);
/*
 <FKUser[name=sun,pass=123]对应的所有key为:(
 one,
 three
 )
 */

(5)、枚举器遍历

//枚举遍历dict所有value的枚举器
NSEnumerator* en = [dict objectEnumerator];
NSObject* value;
//使用枚举器来遍历dict中所有的value
while (value = [en nextObject]) {
    NSLog(@"%@",value);
}
/*
 <FKUser[name=sun,pass=123]>
 <FKUser[name=niu,pass=155]>
 <FKUser[name=sun,pass=123]>
 <FKUser[name=bai,pass=345]>
 <FKUser[name=tang,pass=178]>
 */

(6)、指定代码块执行

//使用指定代码块来迭代执行该集合中所有key-value对
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
    //该集合包含多个key-value对,下面的代码块就执行响应的次数
    NSLog(@"key的值为:%@",key);//key的值为:one
    [obj say:@"疯狂iOS讲义"];//sun说:疯狂iOS讲义
}];

2、对NSDictionary的key排序

NSDictionary还提供了方法对NSDictionary的所有key执行排序,这些方法执行完成后将返回排序完成后的所有key组成的NSArray。方法如下:

  • (1)、keysSortedByValueUsingSelector:根据NSDictionary的所有value的指定方法的返回值对key排序;调用value的该方法必须返回NSOrderedAscending、NSOrderedDescending、NSOrderedSame这三个值之一。
  • (2)、keySortedByValueUsingComparator:该方法使用指定的代码块来遍历key-value对,并根据执行结果(执行结果必须返回NSOrderedAscending、NSOrderedDescending、NSOrderedSame这三个值之一)对NSDictionary的所有key进行排序
  • (3)、keySortedByValueWithOptions:usingComparator:与前一个方法的功能类似,只是该方法可以传入一个额外的NSEnumerationOptions参数。

例如:

(1)、初始化

//直接使用多个value,key的形式创建NSDictionary对象
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:@"Objective-C",@"one",@"Ruby",@"two",@"Python",@"three",@"Perl",@"four", nil];
//打印dict集合的所有元素
[dict print];//{one=Objective-C, three=Python, two=Ruby, four=Perl}

(2)、compare:排序

//获取所有直接调用value的compare:方法对所有的key进行排序
//返回排好序的所有key组成的NSArray
NSArray* keyArr1 = [dict keysSortedByValueUsingSelector:@selector(compare:)];
NSLog(@"%@",keyArr1);
/*
 输出:(one,four,three,two)
 */

(3)、自定义偶排序

NSArray* keyArr2 = [dict keysSortedByValueUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    //对NSDictionary的value进行比较,字符串越长,即可认为该value越大
    if ([obj1 length] > [obj2 length]){
        return NSOrderedDescending;
    }else if ([obj1 length] < [obj2 length]){
        return NSOrderedAscending;
    }else{
        return NSOrderedSame;
    }
}];
NSLog(@"%@",keyArr2);
/*
 输出:(two,four,three,one)
 */

(4)、将字典写入文件

//将NSDictionray的内容输出到指定文件中
[dict writeToFile:@"mydict.txt" atomically:YES];

3、对NSDictionary的key进行过滤

NSDictionary还提供了方法对NSDictionary的所有keu执行过滤,这些方法执行完成后返回卯足过滤条件的key组成NSSet。方法如下:

  • (1)、keysOffEntriesPassingTest:使用代码块迭代处理NSDictionary的每个key-value对。对NSDictionary的key-value进行过滤,该代码块必须返回BOOL类型的值,只有点那个代码块返回YES时,该key才会保留下来;该代码快可以接受三个参数,第一个参数代表正在迭代处理的key,第二个参数代表正在迭代处理的value,第三个参数代表是否还需要继续迭代,如果将第三个参数设为NO,该方法就会立即停止迭代。
  • (2)、keyOfEntriesWithOptions:PassingTest:该方法的功能与前一个方法的功能基本相同。只是该方法可以额外传入一个附加的NSEnumerationOptions选项参数。

例如:

//直接使多个value,key的形式创建NSDictionary对象
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:89],@"Objective-C",[NSNumber numberWithInt:69],@"Ruby",[NSNumber numberWithInt:75],@"Python",[NSNumber numberWithInt:109],@"Perl", nil];
//打印dict集合的所有元素
[dict print];//{Perl=75, Objective-C=89, Python=75, Ruby=69}
//对NSDictionary的所有key进行过滤
NSSet* keySet = [dict keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) {
    //对NSDictionary的value进行比较,字符串越长,即可认为该value越大
    //当value的值大于80时返回YES
    //这就意味着只有value的值大于80的key才会被保存下来
    return (BOOL)([obj intValue] > 80);
}];
NSLog(@"%@",keySet);//{("Perl,Objective-C")}

4、使用自定义类作为NSDictionary的key

自定义类必须满足如下条件

  • (1)、该自定义类正确写过isEqual:和hash方法。所谓正确重写,是指当两个对象通过isEqueal:方法判断相等时,两个对象费Hash方法返回值也相等。
  • (2)、该自定义类必须实现copyWithZone:方法,该方法最好返回对象的不可变副本。

    提示:只要程序把任何对象作为key放入NSDictionary时,NSDictionary总会先调用该key的copy方法来复制该对象的不可变副本,然后使用该副本作为NSDictionary的key。
    

例如:

FKUser遵守NSCopying协议,实现方法

- (id)copyWithZone:(NSZone *)zone{
    NSLog(@"--正在复制--");
    //复制一个对象
    FKUser* newUser = [[[self class]allocWithZone:zone]init];
    //将复制的对象的实变量赋给新对象的实例变量
    newUser->name = name;
    newUser->pass = pass;
    return newUser;
}
FKUser* ul = [[FKUser alloc]initWithName:@"bai" pass:@"345"];
//直接使用多个value,key的形式创建NSDictionary对象
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:@"one",[[FKUser alloc]initWithName:@"sun" pass:@"123"],@"two",ul,@"three",[[FKUser alloc]initWithName:@"sun" pass:@"123"], @"four",[[FKUser alloc]initWithName:@"tang" pass:@"178"],@"five",[[FKUser alloc]initWithName:@"niu" pass:@"155"],nil];
//将ul的密码设为nil
ul.pass = nil;
//由于NSDictionary并未直接使用ul所指向的FKUser作为key,而是先复制了ul所指向的对象的副本,然后以该副本作为key,因此程序将可以看到dict的key不会受到任何影响
[dict print];//{<FKUser[name=tang,pass=178]>=four, <FKUser[name=niu,pass=155]>=five, <FKUser[name=sun,pass=123]>=one, <FKUser[name=bai,pass=345]>=two}

5、NSMutableDictionary的功能与用法

新增方法:

  • (1)、setObject:forKey:设置一个key-value对。如果NSDictionary中没有包含该key相同的key-value,NSDictionary将会增加一个key-value对;否则该key-value将会覆盖已有的key-value对;
  • (2)、setObject:forKeyedSubscript:通过该方法的支持,允许程序通过下标法来设置key-value对;
  • (3)、addEntriesFromDictionary:将另一个NSDictionary中所有的key-value对复制到当前NSDictionary中;
  • (4)、setDictionary:用另一个NSDictionary中所有的key-value对替换当前NSDictionary中的key-value;
  • (5)、removeObjectForKey:根据key来删除key-value对;
  • (6)、removeAllObjects清空NSDictionary;
  • (7)、removeObjectsForKeys:使用多个key组成的NSArray作为参数,同时删除多个key对应的key-value对。

例如:

(1)、初始化

//直接使用多个value,key的形式创建NSDictionary对象
NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:89],@"疯狂Android讲义", nil];

(2)、根据下标添加key值相同的元素

//使用下标法设置key-value对,由于NSDictionary中已经存在该key,因此此处设置的value会覆盖前面的value
dict[@"疯狂Android讲义"] = [NSNumber numberWithInt:99];
[dict print];//{疯狂Android讲义=99}

(3)、再次添加元素

NSLog(@"--再次添加key-value对--");
dict[@"疯狂XML讲义"] = [NSNumber numberWithInt:69];
[dict print];//{疯狂XML讲义=69, 疯狂Android讲义=99}
NSDictionary* dict2 = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:79],@"疯狂Ajax讲义",[NSNumber numberWithInt:89],@"Structs 2.x权威指南", nil];

(4)、将另一个字典添加到字典中

//将另一个NSDictionray中的key-value对添加到当前NSDictionary中
[dict addEntriesFromDictionary:dict2];
[dict print];//{疯狂Ajax讲义=79, 疯狂Android讲义=99, Structs 2.x权威指南=89, 疯狂XML讲义=69}

(5)、删除key-value对

//根据key来删除key-value对
[dict removeObjectForKey:@"Structs 2.x权威指南"];
[dict print];//{疯狂Ajax讲义=79, 疯狂Android讲义=99, 疯狂XML讲义=69}

九、谓词

NSPredicate用于定义一个逻辑条件,通过该条件可执行搜索或内存中的过滤操作。

1、定义谓词

谓词有NSPredicate对象来代表,它有三个子类:NSComparisonPredicate、NSCompoundPredicate和NSExpression,虽然程序实际上创建的通常是NSPredicate的子类的实例,但实际编程时会直接使用NSPredicate的predicateWithFormat:方法,以一个谓词字符串为参数创建NSPredicate对象。
创建谓词之后,如果谓词没有占位符参数,即可使用NSPredicate的evaluateWithObject:方法计算谓词的结果,该结果总是一个BOOL值;如果该谓词中有占位符参数,则需要通过下面两步计算谓词的结果:

  • ①、调用谓词的predicateWithSubstitutionVariables:方法为占位符参数设置参数值;
  • ②、执行谓词的evaluateWithObject:方法计算谓词的返回结果

例如:

NSPredicate* pred = [NSPredicate predicateWithFormat:@"name like 's*'"];
FKUser* user1 = [[FKUser alloc]initWithName:@"sun" pass:@"123"];
//对user1对象使用谓词执行判断
BOOL result1 = [pred evaluateWithObject:user1];
NSLog(@"user1的name是否以s开头:%d",result1);//user1的name是否以s开头:1
FKUser* user2 = [[FKUser alloc]initWithName:@"bai" pass:@"563"];
//对user2对象使用谓词进行判断
BOOL result2 = [pred evaluateWithObject:user2];
NSLog(@"user2的name是否以s开头:%d",result2);//user2的name是否以s开头:0

4、谓词表达式

  • 1、基本的比较运算符
    • (1)、=、==:判断两个表达式是否相等;
    • (2)、>=、=>:判断左边表达式的值是否大于或等于右边表达式的值;
    • (3)、<=、=<:判断左边表达式的值是否小于或等于右边表达式的值;
    • (4)、>:判断左边表达式的值是否大于右边表达式的值;
    • (5)、<:判断左边表达式的值是否小于右边表达式的值;
    • (6)、!=、<>:判断两个表达式是否不相等;
  • 2、基本的逻辑运算符
    • (1)、AND、&&:逻辑与,要求两个表达式的值都为YES时,结果才是YES;
    • (2)、OR、||:逻辑或,要求任何一个表达式的值为YES,结果才是YES;
    • (3)、NOT、!:逻辑非,用于对原有的表达式结果取反;
  • 3、字符串比较运算符
    • (1)、BEGINSWITH:检查某个字符串是否以指定的子串开头;
    • (2)、ENDSWITH:检查某个字符串是否以指定的子串结尾;
    • (3)、CONTAINS:检查某个字符串是否包含指定的子串;
    • (4)、LIKE:检查某个字符串是否匹配指定的字符串模板;
    • (5)、MATCHES:检查某个字符串是否匹配指定的正则表达式;

十、本章小结

本章主要介绍了Foundation框架的核心API,这些核心API不仅是开发iOS应用的基础,也是开发OS X应用的基础。Foundation核心API包括:字符串、日期和时间相关类、对象赋值,以及集合类,都是iOS应用开发最常见的API。
本章的重点是Foundation的集合类:数组(NSArray)、集合(NSSet)、有序集和(NSOrderesSet)以及字典(NSDictionary)。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值