iOS学习-- Foundation框架

字符串(NSString和NSMutableString)

NSString代表字符序列不可变的字符串,NSMutableString代表字符序列可变的字符串

创建字符串

NSString的功能非常强大,大致包括如下功能

  • 创建字符串:创建字符串既可使用以init开头的实例方法,也可使用以string开头的类方法,当然也可以直接用@""的形式给出字符串直接量。
  • 读取文件或网络URL来初始化字符串。
  • 将字符串内容写入文件或URL。
  • 获取字符串长度,既可获取字符串内包括的字符个数,也可获取字符串包括的字节个数。
    获取字符串中的字符或字节,既可获取指定位置的字符,也可获取指定范围的字符。
  • 获取字符串对应的C风格字符串。
  • 连接字符串。
  • 分隔字符串。
  • 查找字符串内指定的字符和子串。
  • 替换字符串。
  • 比较字符串。
  • 字符串大小比较。 ??与上面有什么区别
  • 对字符串中的字符进行大小写转换。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        unichar data[6] = {97,98,99,100,101,102}; //unichar数组就是unsigned short的别名
        NSString *str = [[NSString alloc] initWithCharacters:data length:6];
        NSLog(@"%@",str);
        char *cstr = "Hello, iOS!";
        NSString *str2 = [NSString stringWithUTF8String:cstr];
        NSLog(@"%@",str2);
        [str2 writeToFile:@"myFile.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];//文件在哪????
        NSString* str3 = [NSString stringWithContentsOfFile:@"NSStringTest.m" // 如何读入
                                                   encoding:NSUTF8StringEncoding error:nil];
        NSLog(@"%@",str3);
    }
}

上面简单示范了创建NSString对象的三种方式。

NSString的常用功能

以程序示例

#import <Foundation/Foundation.h>
#import "FKUser.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSString* str = @"我爱玩";
        NSString* game = @"原神";
        str = [str stringByAppendingString:@"原神!"];
        NSLog(@"%@",str);
        const char* cstr = [str UTF8String];
        NSLog(@"获取的C字符串:%s",cstr);
        str = [str stringByAppendingFormat:@"%@是一款3a巨作",game];
        NSLog(@"%@" , str);
        NSLog(@"str的字符个数为:%lu",[str length]);
        NSLog(@"str按UTF-8字符集解码后字节数为:%lu",[str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
        NSString *s1 = [str substringToIndex:5];
        NSLog(@"%@",s1);
        NSString *s2 = [str substringFromIndex:6];
        NSLog(@"%@",s2);
        NSString *s3 = [str substringWithRange:NSMakeRange(6, 7)];
        NSLog(@"%@",s3);
        NSRange pos = [str rangeOfString:@"原神"];
        NSLog(@"原神在str中出现的开始位置:%ld,长度为:%ld", pos.location,pos.length);
        str = [str uppercaseString];
        NSLog(@"%@",str);
    }
}

对字符串个数和位置有一点疑惑。需要解决。

NSMakeRange 函数

声明如下:

objective

复制

NSRange NSMakeRange(NSUInteger location, NSUInteger length);
  • location:表示范围的起始位置(索引),从 0 开始计数。
  • length:表示范围的长度,即包含的元素个数。

可变字符串

NSString是不可变类,一旦NSString对象被创建,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。

NSMutableString对象则代表一个字符序列可变的字符串

改变序列的方法:
示例:

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSString *game = @"永劫无间";
        NSMutableString* str = [NSMutableString stringWithString:@"玩游戏"];
        [str appendString:@"我只打劫。"];
        NSLog(@"%@",str);
        [str appendFormat:@"%@是世界上最好的游戏",game];
        NSLog(@"%@",str);
        [str insertString:@"哈哈" atIndex:0];
        NSLog(@"%@",str);
        [str deleteCharactersInRange:NSMakeRange(0, 10)];
        NSLog(@"%@",str);
        [str replaceCharactersInRange:NSMakeRange(0,5) withString:@"原神"];
        NSLog(@"%@",str);//疑问,对字符串的位置和越界问题
    }
}

NSMutableString类:可变字符串

NSMutableString 类是 Objective-C 中的一个可变字符串类,它是 NSString 类的子类。相对于 NSString 的不可变性,NSMutableString 具有以下作用和特点:

  1. 可变性(Mutability)NSMutableString 对象是可变的,这意味着可以对其进行修改、添加和删除操作。你可以在已有字符串的基础上进行更改,而无需创建新的字符串对象。这种可变性使得 NSMutableString 在需要频繁操作字符串的情况下更加高效。

  2. 追加和插入操作NSMutableString 提供了一系列方法用于在字符串末尾追加字符、字符串或格式化的文本。你可以使用 appendString:appendFormat:insertString:atIndex: 等方法来实现字符串的追加和插入操作。

    1. appendString:appendString: 方法用于将指定的字符串追加到可变字符串的末尾。
  NSMutableString *mutableString = [NSMutableString stringWithString:@"Hello"];//请注意,stringWithString:方法实际上是NSString类的一个便捷方法,等效于使用[[NSString alloc] initWithString:]来创建字符串的副本。
  [mutableString appendString:@" World!"];
  NSLog(@"%@", mutableString); 
  1. appendFormat::方法用于将格式化的文本追加到可变字符串的末尾。

  2. insertString:atIndex:insertString:atIndex: 方法用于在可变字符串的指定位置插入指定的字符串。下图即插入索引5。

  NSMutableString *mutableString = [NSMutableString stringWithString:@"Hello!"];
  [mutableString insertString:@" World" atIndex:5];
  NSLog(@"%@", mutableString); // Output: Hello World!
  1. 删除和替换操作:除了追加和插入操作,NSMutableString 还提供了删除和替换字符串的方法。你可以使用 deleteCharactersInRange:replaceOccurrencesOfString:withString:options:range: 等方法来删除或替换字符串中的特定部分。

  2. 可变长度NSMutableString 的长度是可变的。你可以在字符串中插入或删除字符,从而改变字符串的长度,而不会引起异常或错误。

  3. 与其他字符串类的转换NSMutableString 可以与其他字符串类进行相互转换。你可以通过 mutableCopy 方法将不可变的 NSString 对象转换为可变的 NSMutableString 对象,反之亦然。

需要注意的是,由于 NSMutableString 是可变的,它并不适用于需要保持字符串不变的情况。如果你有一个字符串不需要修改,并且希望确保其内容不会被意外更改,应该使用不可变的 NSString 类。

日期与时间

NSdate

NSdate对象代表日期与时间,既可以通过类方法创建NSDate对象,也可以通过init实例方法来初始化NSDate对象。

下面是一些创建的实例:

#import <Foundation/Foundation.h>
#import "FKUser.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSDate *date1 = [NSDate date];
        NSLog(@"%@",date1);
        NSDate *date2 = [[NSDate alloc] initWithTimeIntervalSinceNow:3600*24];
        NSLog(@"%@",date2);
        NSDate *date3 = [[NSDate alloc ] initWithTimeIntervalSinceNow: -365*3600*24*19];
        NSLog(@"%@",date3);
        NSDate* date4 = [NSDate dateWithTimeIntervalSince1970:3600 * 24 * 366 * 20];
        NSLog(@"%@",date4);
        NSLocale* cn = [NSLocale currentLocale];
        NSLog(@"%@",[date1 descriptionWithLocale:cn]);
        NSDate *earlier = [date1 earlierDate:date2];
        NSDate *later = [date1 laterDate:date2];
        switch ([date1 compare:date3]) {
            case NSOrderedAscending:
                NSLog(@"date1位于date3之前");
                break;
            case NSOrderedSame:
                NSLog(@"date1与date3日期相等");
                break;
            case NSOrderedDescending:
                NSLog(@"date1位于date3之后");
                break;
        }
        NSLog(@"date1与date2之间时间差%g秒", [date1 timeIntervalSinceDate:date3]);
        NSLog(@"date2与现在时间间差%g秒", [date2 timeIntervalSinceNow]);//%g自动选择%f或者%e,输出宽度较短的格式,且不输出无意义的0
    }
}

compare方法与NSComparisonResult枚举类型

NSOrderedAscendingNSComparisonResult枚举类型的一个成员之一。NSComparisonResult用于表示比较两个对象的结果,包括三个可能的取值:NSOrderedAscendingNSOrderedSameNSOrderedDescending

NSOrderedAscending表示第一个对象在排序中应该排在第二个对象之前。换句话说,第一个对象的值较小或者按照排序规则较早。

通常,用于比较的方法会返回NSComparisonResult类型的值,以指示两个对象的比较结果。例如,当使用compare:方法比较两个NSString对象时,返回的值可能是NSOrderedAscendingNSOrderedSameNSOrderedDescending

注意:NSOrderedAscendingNSOrderedSameNSOrderedDescending。为常量,是使用compare的返回值。

使用实例: 待深入了解

   switch ([date1 compare:date3]) {
        case NSOrderedAscending:
            NSLog(@"date1位于date3之前");
            break;
        case NSOrderedSame:
            NSLog(@"date1与date3日期相等");
            break;
        case NSOrderedDescending:
            NSLog(@"date1位于date3之后");
            break;
    }

日期格式器

NSDateFormatter代表一个日期格式器,功能为完成NSDate与NSString之间的转换。步骤如下:

  1. 创建一个NSDateFormatter对象。

  2. 调用setDateStyle: ,setTimeStyle:方法设置格式化日期时间的风格。

    • NSDateFormatterNoStyle:不显示日期时间的风格

    • NSDateFormatterShortStyle:显示“短”的日期时间风格。

    • NSDateFormatterMediumStyle:显示“中”的日期时间风格。

    • NSDateFormatterLongStyle:显示“长”的日期时间风格。

    • NSDateFormatterFullStyle:显示“完整”的日期时间风格。

      还可以调用NSdateFormatter和setDateFormate:方法设置自己的模板

  3. 如果要将NSDate转换为NSString,调用NSDateFormatter的string FromDate:方法执行格式化。

  4. 如果要将NSString转换为NSDate,调用NSDateFormatter的dateFromString:方法执行格式化。

#import <Foundation/Foundation.h>
#import "FKUser.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSDate* dt = [NSDate dateWithTimeIntervalSince1970:3600*24*366*20];
        NSLocale* locales[] = {[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"],
            [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]};
        NSDateFormatter* df[8];
        for (int i = 0; i < 2; i++) {
            df[i * 4] = [[NSDateFormatter alloc] init];
            [df[i * 4] setDateStyle:NSDateFormatterShortStyle];
            [df[i * 4] setTimeStyle:NSDateFormatterShortStyle];
            [df[i * 4] setLocale:locales[i]];
            
            df[i * 4 + 1] = [[NSDateFormatter alloc] init];
            [df[i * 4 + 1] setDateStyle:NSDateFormatterMediumStyle];
            [df[i * 4 + 1] setTimeStyle:NSDateFormatterMediumStyle];
            [df[i * 4 + 1] setLocale:locales[i]];
            
            df[i * 4 + 2] = [[NSDateFormatter alloc] init];
            [df[i * 4 + 2] setDateStyle:NSDateFormatterLongStyle];
            [df[i * 4 + 2] setTimeStyle:NSDateFormatterLongStyle];
            [df[i * 4 + 2] setLocale:locales[i]];
            
            df[i * 4 + 3] = [[NSDateFormatter alloc] init];
            [df[i * 4 + 3] setDateStyle:NSDateFormatterFullStyle];
            [df[i * 4 + 3] setTimeStyle:NSDateFormatterFullStyle];
            [df[i * 4 + 3] setLocale:locales[i]];
        }
        for (int i = 0; i < 2 ;i++) {
            switch (i)
            {
                case 0:
                    NSLog(@"------中国日期格式------");
                    break;
                case 1:
                    NSLog(@"------美国日期格式------");
                    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]);
          
    NSString *dateStr = @"2024-01-01-01-50-50";
    NSDateFormatter *df1 = [[NSDateFormatter alloc] init];
    [df1 setDateFormat:@"yyyy-MM-dd-hh-mm-ss"];
    NSDate* date2 = [df1 dateFromString: dateStr];
    NSLog(@"%@",date2);//好神奇的输出
    //    NSString *dateStr = @"2024-01-01";
    //    NSDateFormatter *df1 = [[NSDateFormatter alloc] init];
    //    [df1 setDateFormat:@"yyyy-MM-dd"];
        }
    }
}

日历与日期组件

对象复制

copy与mutableCopy方法

两者都是复制一个对象的副本,copy方法返回对象的不可修改的副本。mutableCopy方法返回对象可修改的副本。

简而言之,返回的对象可不可以修改,与原本的字符串对象无关,与用哪个方法有关。

如程序调用NSString的mutableCopy方法,将会返回一个NSMutableString对象。

二者对返回原对象的副本,对复制的副本进行修改,原对象通常不会收到影响。

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSMutableString* heart = [NSMutableString stringWithString:@"cold"];
        NSMutableString* heartCopy = [heart mutableCopy];
        [heartCopy replaceCharactersInRange:NSMakeRange(0, 4) withString:@"hot"];
        NSLog(@"heart是:%@",heart);
        NSLog(@"heartCopy是:%@",heartCopy);
        NSString *str = @"cold";
        NSMutableString *strCopy = [str mutableCopy];
        [strCopy appendString:@" become hot"];
        NSLog(@"%@",strCopy);
        NSMutableString *heart2 = [heart copy];
        //[heart2 appendString:@"become hot"];
    }
}

只要用mutableCopy复制的副本都可变。用Copy复制的副本不可变

NSCopying与NSMutableCopy协议

保证一个对象可调用copy方法来复制自身到不可变副本,通常需要做如下事情:

  • 让该类实现NSCopying协议. (协议内容即下面的方法)
  • 让该类实现copyWithZone:方法

保证一个对象可调用mutableCopy方法来复制自身到可变副本,通常需要做如下事情

  • 让该类实现NSMutableCopying协议
  • 让该类实现mutableCopyWithZone:方法

调用上述两种方法的返回实际上就是返回copyWithZone和mutableCopyWithZone的返回值。

示例:

//.h
#import <Foundation/Foundation.h>

@interface Dog : NSObject
@property (nonatomic, strong) NSMutableString* name;
@property (nonatomic, assign) int age;
@property (nonatomic, strong) NSString* variety;
@end
//.m

#import "Dog.h"
@implementation Dog
@synthesize name;
@synthesize age;
@synthesize variety;
- (id) copyWithZone:(NSZone*)zone
{
    NSLog(@"--执行copyWithZone--");
    Dog* dog = [[[self class] allocWithZone:zone] init];//self class的作用是获取当前对象所属的类,用于动态创建与当前对象类型相同的新对象。这样可以确保在继承关系中正确地创建副本,并保持类型的一致性。 !!!!!!!!!!!!!!
    dog.name = self.name;
    dog.age = self.age;
    dog.variety = self.variety;
    return dog;
}
@end
//
#import <Foundation/Foundation.h>
#import "Dog.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Dog* dog1 = [[Dog alloc] init];
        dog1.name = [NSMutableString stringWithString:@"毛毛"];
        dog1.age = 8;
        dog1.variety = @"VIP";
        Dog* dog2 = [dog1 copy];
        dog2.name = [NSMutableString stringWithString:@"多多"];
        dog2.age = 7;
        NSLog(@"dog1的名字为:%@",dog1.name);
        NSLog(@"dog1的年龄为:%d",dog1.age);
        NSLog(@"dog1的品种为:%@",dog1.variety);
        NSLog(@"dog2的名字为:%@",dog2.name);
        NSLog(@"dog2的年龄为:%d",dog2.age);
        NSLog(@"dog2的品种为:%@",dog2.variety);
    }
    return 0;
}

上述程序即实现了NSCopying协议并实现了copyWithZone:方法。- (id) copyWithZone:(NSZone*)zone该方法的zone参数与不同的储存区有关,通常无需过多的关心该程序。

重写Zone方法时,父类已经实现了NSCopying协议,并重写过copyWithZone方法,那么子类重写时应该调用父类的copy方法复制从父类继承得到的成员变量,然后对子类中定义的成员变量进行赋值。

格式如下:

- (id)copyWithZone:(NSZone*)zone
{
	id obj = [super copy];
  //对子类定义的成员变量赋值
  
  return obj;
}

深浅复制

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Dog* dog1 = [[Dog alloc] init];
        dog1.name = [NSMutableString stringWithString:@"毛毛"];
        Dog* dog2 = [dog1 copy];
        [dog2.name replaceCharactersInRange: NSMakeRange(0,2 ) withString:@"多多"];
        NSLog(@"dog1的名字为:%@",dog1.name);
        NSLog(@"dog2的名字为:%@",dog2.name);

    }
    return 0;
} // out: 多多。多多。

上面的程序调用dog1的copy方法复制了一个副本,并将副本赋给dog2变量。当接下来修改dog2.name属性值时,输出dog1/dog2两个对象多多name属性,编译运行发现两者都发生改变。都变成了多多。为什么呢?

这就是程序的浅复制。即未复制对象,而是复制指针地址。

当创建第一个Dog对象时,并使用dog1指针指向对象后的内存存储示意图:

查看copyWithZone方法的代码:

dog.name = self.name;
dog.age = self.age;

dog代表复制出来的对象。程序将被复制对象的name赋值给dog对name。但name只是一个指针变量,存放的只是字符串的地址,并不是字符串本身。发上了浅复制。如图所示

​ 我是图图

浅复制:当对象的实例变量是指针变量是,如果程序只是复制该指针的地址,而不是真正复制指针所指向的对象,这种方式被称为浅复制。

深复制:不仅会复制对象本身,而且会递归复制每个指针类型的实例变量,直到两个对象没有任何公共部分。修改如下:

-(void)copyWithZone:(NSZone*)zone
{
  NSLog(@"--执行copyWithZone--");
  Dog* dog = [[[self class] allocWithZone:zone] init];
  dog.name = [self.name mutableCopy];
  dog.age = self.age;
  return dog;
}

先讲name实例变量复制一份可变副本,再将该可变副本的值赋给新对象的name实例变量。保证二者没有任何公用部分,实现了深复制。

setter方法的复制选项

setter和getter方法可以使用copy指示符。就是指定当程序调用setter方法复制时,实际上是将传入参数的副本赋给程序的实例变量。

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface ttsetter : NSObject
@property (nonatomic , copy) NSMutableString* name;
@end

NS_ASSUME_NONNULL_END
  
#import "ttsetter.h"

@implementation ttsetter
@synthesize name;
@end
  
#import <Foundation/Foundation.h>
#import "Dog.h"
#import "FKSon.h"
#import "ttsetter.h";
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        ttsetter* test1 = [ttsetter new];
        test1.name = [NSMutableString stringWithString:@"超级3g"];
        [test1.name appendString:@"超级西柚"];//失败。

    }
    return 0;
}

上述代码无法正确使用appendString方法的原因:setter方法的代码为copy

-(void) setName:(NSMutableString*) aname
{
	name = [aname copy];
}

默认复制该对象的不可变副本,因此上述程序调用该参数的copy方法得到的是不可变副本。

oc集合概述

大致分为NSArray,NSSet,NSDictionary三类。

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

为了保存数量不确定的数据,以及保存具有映射关系的数据(关联数组),oc提供了集合类。集合类主要负责保存其他数据,也称为容器类。oc的集合分别由NSArray,NSSet,NSDictionary这三个类簇代表,还有NSMUtableArray,NSMutableSet,NSMutableDictionary三个字子类。
在这里插入图片描述

集合类与数组不同,数组元素既可以是基本类型的值,也可以是对象(实际上保存的是对象的指针变量);而集合只能保存对象(实际上只是保存对象的指针变量。)

  • NSSet集合类似于罐子,无法记住添加元素的顺序,因此NSSet里的元素不能重复,否则无法准确识别出这个元素。
  • NSArry集合类似于数组,可以记住每次添加元素的顺序,只是NSMutableArray的长度可变。
  • NSDictionary集合也像一个罐子也像一个罐子,只是里面的每项数据都由两个值组成。

访问:

  • NSArray集合中的元素直接根据元素的索引访问
  • NSDictionary集合中的元素可以根据每项元素的其中一个访问另一个。
  • NSSet集合中的元素只能根据元素本身来访问。这也是不允许重复的原因

NSEnumerationOptions参数

NSEnumerationConcurrent:并发迭代。多个元素可以同时并发处理,可能会以更快的速度完成迭代,但是顺序不确定。
NSEnumerationReverse:反向迭代。按照逆序处理集合的元素。
NSEnumerationOrdered:有序迭代。保持迭代顺序与集合元素的顺序一致。在默认情况下,迭代是无序的。

数组(NSArray与NSMutableArray)

NSArray的功能和用法

可用类方法(array开头)或者实例方法(init)开头。常见方法介绍:

  • array:创建一个不包含任何元素的空NSArray。
  • arrayWithContentsOfFile: / initWIthContentsOfFile: :读取文件内容来创建NSArray
  • arrayWithObject: / initWithObject: :创建只包含指定一个元素的NSArray
  • arrayWithObjects: / initWithObjects: :创建包含指定的N个元素的NSArray
  • 简化语法:@[元素1,元素2,元素3……]
  • 查询集合元素在NSArray中的索引
  • 根据索引值取出NSArray集合中的元素
  • 对集合元素整体调用方法
  • 对NSArray集合进行排序
  • 取出NSArray集合中的部分集合组成新集合
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
NSArray *array = [NSArray
                 arrayWithObjects:@"季莹莹",@"胡桃",@"哈迪",@"殷紫萍", nil];
        NSLog(@"第一个元素:%@",[array objectAtIndex:0]);
        NSLog(@"第一个元素:%@",[array firstObject]);
        NSLog(@"索引为1的元素:%@",[array objectAtIndex:1]);
        NSLog(@"最后的一个元素:%@",[array lastObject]);
        NSArray *arr1 = [array objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 2)]];
        NSLog(@"zhelizhelizheli%@",arr1);
        NSLog(@"殷紫萍的位置为:%ld",[array indexOfObject:@"殷紫萍"]);
        NSLog(@"殷紫萍在1-2的位置为:%ld",[array indexOfObject:@"殷紫萍" inRange:NSMakeRange(1, 1)]);
        array = [array arrayByAddingObject:@"刘炼"];
        array = [array arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:@"水万象",@"火万象", nil]];
        for (int i = 0 ; i< array.count; i++){
            NSLog(@"%@",array[i]);
        }
        NSArray* arr2 = [array subarrayWithRange:NSMakeRange(1, 3)];
        [arr2 writeToFile:@"/Users/liuyuanfu/Desktop/笔记/未命名.txt " atomically:YES];
    }
    return 0;
}

输出展示

上面是一段示例代码。注意array[i]的方法在IOS5.0系统以上才能使用。

NSArray判断集合包含元素的标准:只有某个集合元素与被查找元素通过isEqual:方法比较返回YES,即认为包含该方法。

对集合元素整体调用方法

简单调用有两种方法:

  • makeObjectsPerformSelector::依次调用NSArray集合中每个元素的指定方法,该方法需要传入一个SEL参数,用于指定调用哪种方法。
[array makeObjectsPerformSelector:@selector(someMethod)];//格式如上,该方法不能带有参数。

该方法需要注意两点:

  1. 被调用的方法必须没有参数和返回值,因为 makeObjectsPerformSelector: 方法不会传递任何参数,并且不关心方法的返回值。
  2. 如果数组中的某个对象不响应指定的方法,即该对象的类没有实现指定的方法,会引发运行时错误。
  • **makeObjectsperformSelector:withObjects:**依次调用NSArray集合中每个元素的指定方法,第一个SEL参数用于指定方法,第二个参数用于调用时传入参数,第三个参数用于控制是否终止迭代。
- (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(nullable id)object1 withObject:(nullable id)object2;//方法定义

该方法为实例方法,所以需要传入参数。如下图所示:

NSArray *array = @[obj1, obj2, obj3];
[array makeObjectsPerformSelector:@selector(someMethod:withParam2:) withObject:param1 withObject:param2];

该方法会将param1和param2作为参数传入前面的方法。

使用该方法需要注意:

  1. 被调用的方法必须具有两个参数,并且可以没有返回值。
  2. 如果被调用的方法有返回值,makeObjectsPerformSelector:withObject:withObject:方法将忽略返回值。
  3. 被调用的方法必须是可响应的,即对象的类必须实现指定的方法,否则会引发运行时错误。

如果想要对集合所有元素进行隐式的遍历,并使用集合元素来执行某一段代码,则可通过如下方法解决:

  • enumerateObjectsUsingBlock::遍历集合中的所有元素,并以此使用元素来执行指定代码块。

语法:

[array enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
    // 执行代码块的操作,可以使用 object 来访问当前元素
}];

参数:

object:当前遍历到的元素。

index:当前元素的索引。

*stop:一个指针,用于控制是否终止遍历。在代码块内部设 *stop = YES可以提前结束遍历。

  • enumerateObjectsWithOptions:usingBlock::该方法可以额外传入一个参数,用于控制遍历的选项,如反向遍历。

语法:

[collection enumerateObjectsWithOptions:(NSEnumerationOptions)options usingBlock:^(id object, NSUInteger index, BOOL *stop) {
    // 执行代码块的操作,可以使用 object 来访问当前元素
}];

参数:除上个方法的三个参数外,还有options参数。

options:一个枚举类型的参数,用于控制遍历选项,如反向遍历(NSEnumerationReverse)等。

  • enumerateObjectsAtIndexes:options:usingBlock::遍历集合中指定范围内的元素,并依次使用元素来执行指定的代码块。可以额外传入一个选项参数,用于控制遍历的选项,如反向遍历。

语法:

[collection enumerateObjectsAtIndexes:(NSIndexSet *)indexes options:(NSEnumerationOptions)options usingBlock:^(id object, NSUInteger index, BOOL *stop) {
    // 执行代码块的操作,可以使用 object 来访问当前元素
}];

参数:除了options外,还有一个indexes参数来实现遍历集合中指定范围内的元素。

indexes:一个 NSIndexSet 对象,指定要遍历的元素的索引集合。

options:一个枚举类型的参数,用于控制遍历选项,如反向遍历(NSEnumerationReverse)等。

其他参数和示例与前两个方法类似。

上面即是所有方法的详解,现在来实操一下这些方法吧。

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface lncoketest1 : NSObject
@property (nonatomic , copy) NSString *name;
@property (nonatomic , copy) NSString *weapon;
- (void) say;
- (void) say1:(NSString*) content;
-(id) initWithName:(NSString*) aName weapon:(NSString*)aweapon;
@end

NS_ASSUME_NONNULL_END


#import "lncoketest1.h"

@implementation lncoketest1
@synthesize name;
@synthesize weapon;
- (void) say
{
    NSLog(@"%@喜欢%@",self.name,self.weapon);
}
-(id) initWithName:(NSString*) aname weapon:(NSString*)aweapon
{
    if(self = [super init])
    {
        name = aname;
        weapon = aweapon;
    }
    return self;
}
- (void) say1:(NSString*) content
{
    NSLog(@"%@说:%@",self.name,content);
}
@end


#import "lncoketest1.h"
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
       NSArray *array = [NSArray arrayWithObjects:
                         [[lncoketest1 alloc] initWithName:@"殷紫萍" weapon:@"太刀"],
                         [[lncoketest1 alloc] initWithName:@"胡桃" weapon:@"长剑"],
                         [[lncoketest1 alloc] initWithName:@"妖刀姬" weapon:@"斩马刀"],
                         [[lncoketest1 alloc] initWithName:@"哈迪" weapon:@"扇子"],
                         [[lncoketest1 alloc] initWithName:@"季莹莹" weapon:@"棍子"],
                         nil];
        [array makeObjectsPerformSelector:@selector(say)];
        NSString *content = @"我想当天选";
      //此处还可以使用:
      //NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 4)];
      //用indexes替换下面的[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2,2)] 使代码简洁。
        [array enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2,2)] options:NSEnumerationReverse 					usingBlock:^(id obj, NSUInteger idx, BOOL * stop) //隐式方法的使用。用options反向遍历。
         {
            [obj say1:content];
         }];
    }
    return 0;


}

上述代码即展示了调用集合中所有元素整体的方法,通过NSIndexSet来控制只对集合中部分元素迭代调用指定的代码块,通过options反向调用等方法。

在这里插入图片描述

对NSArray进行排序

排序终于可以直接sort啦

  • sortedArrayUsingFunction:context::该方法使用排序函数对集合元素进行排序,该排序函数必须返回NSOrderedDescending(降序),NSOrderedAscending(升序),NSOrderedSame(相等)这些枚举值,用于代表集合元素的大小,该方法返回一个排好序的新NSArray对象。
  • sortedArrayUsingSelector::该方法使用集合元素自身的方法对集合元素排序,同样必须返回上个方法的三种枚举值用于代表集合元素的大小,返回一个排好序的新NSArray对象。
  • sortedArrayUsingComparator::该方法使用代码块对集合元素进行排序,其他与上述方法相同。
#import <Foundation/Foundation.h>
//排序函数
NSInteger intSort(id num1, id num2, void *context){
    int v1 = [num1 intValue];
    int v2 = [num2 intValue];
    if (v1 < v2) {
        return NSOrderedAscending;
    } else if (v1 > v2) {
        return NSOrderedDescending;
    } else {
        return NSOrderedSame;
    }
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSArray *array1 = [NSArray arrayWithObjects:@"Objecetive-C",@"C",@"C++",@"Ruby",@"Perl",@"Python",nil];
        array1 = [array1 sortedArrayUsingSelector:@selector(compare:)];//集合元素的compare:方法进行排序
        NSLog(@"%@", array1);
        NSArray *array2 = [NSArray arrayWithObjects:
                           [NSNumber numberWithInt:20],
                           [NSNumber numberWithInt:12],
                           [NSNumber numberWithInt:-8],
                           [NSNumber numberWithInt:50],
                           [NSNumber numberWithInt:19],nil];
        array2 = [array2 sortedArrayUsingFunction:intSort context:nil];//使用intSort函数进行排序
        NSLog(@"%@",array2);
        NSArray *array3 = [array2 sortedArrayUsingComparator:^(id obj1, id obj2) {//使用代码块对元素集合进行排序
            {
                if ([obj1 intValue] > [obj2 intValue]) {
                    return NSOrderedDescending;
                }
                if ([obj1 intValue] < [obj2 intValue]) {
                    return NSOrderedAscending;
                }
                return NSOrderedSame;
            }
        }];
        NSLog(@"%@",array3);
    }
    return 0;
}

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

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

  • objectEnumerator:返回NSArray集合的顺序枚举器
  • reverseObjectEnumerator:返回NSArray集合的逆序枚举器

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

  • allObject:获取被枚举集合的所有元素
  • nextObject:获取被枚举集合中的下一个元素

一般情况下接触nextObjcet方法即可完成对集合元素进行枚举:可采用循环不断获取nextObject方法的返回值,知道该方法的返回值为nil结束循环

int main(int argc, const char * argv[]) {
    @autoreleasepool {
	NSArray *array = [NSArray arrayWitid hContentsOfFile:
                     @"weijianweizhi"];
    NSEnumerator *en = [array objectEnumerator];
    id object;
    while (object = [en nextobject]) {
        NSLog(@"%@",object);
    }
    NSLog(@"-----逆序遍历-----");
    en = [array reverseObjectEnumerator];
    while (object = [en nextobject]) {
        NSLog(@"%@",object);
    }
    }
    return 0;
}

该代码实现了顺逆序两种方式遍历NSArray集合中的元素。

快速枚举(for…in)

使用快速枚举遍历集合元素时,无需获得集合的长度,也无需根据索引来访问集合元素。

for (type variableName in collection)
{
    //variableName 自动迭代访问每个元素...
}

type是集合元素的类型,variableName是一个形参名,快速枚举将自动将集合元素依次赋给该变量。

示例:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
		NSArray *array = [NSArray arrayWithContentsOfFile:
                     @"wenjianweizhi"];
        for(id object in array){
            NSLog(@"%@", object);
        }
    }
    return 0;
}

上述代码不需要数组长度也无须根据索引来访问数组元素。快速枚举的本质是一个foreach循环。

foreach循环:无需循环条件,无须循环迭代语句,这些部分由系统完成。foreach循环自动迭代数组的每个元素,当每个元素都被迭代一次后,foreach循环自动结束。

使用foreach循环遍历NSArray时,元素会按照其在数组中的顺序依次被访问。即按照元素在数组中的索引顺序进行遍历。

使用foreach循环遍历NSSet时,元素的访问顺序也是无序的,因为NSSet是无序的元素集合。

使用foreach循环遍历NSDictionary时,元素的访问顺序并不是固定的,因为NSDictionary是无序的键值对集合。元素的访问顺序可能会受到哈希算法、键的顺序等因素的影响。 (实际操作中是按照映射关系输出)

可变数组

NSArray代表集合元素不可变的集合,一旦创建成功,程序不能进行增删改。

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

NSArray的子类:NSMutableArray可以实现增删改功能,方法如下:

  • 添加集合元素的方法:add开头
  • 删除集合元素的方法:remove开头
  • 替换集合元素的方法:replace开头
  • 插入元素的方法:insert开头
  • 对集合本身排序的方法:sort开头

注意:NSArray的三个sort方法是返回一个新的,排好序的NSArray对象,对NSMutableArray一样适用,此处的则是对集合本身排序

#import <Foundatoin/Foundation.h>

NSString *NSCollectionToString(NSArray *array)
{
	NSMutableString *result = [NSMutabelString stringWithstring:@"["];
	for(id obj in array)
	{
		[result appendString:[obj description]];
		[result appending:@","];
	}
	NSUinteger len = [result length];
	[result deleteCharactersInRange:NSMakeRange(len - 2, 2)];
	[result appendString:@"]"];
	return result;
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {
		NSMutableArray * array = [NSMutableArray arrayWithContentsOfFile:@"wenjianrujing"];
        [array addObject:@"chaojue"];
        NSLog(@"最后追加以个元素后:%@",NSCollectionToString(array));
        [array addObjectsFromArray:@"a",@"b",nil];
        NSLog(@"最后追加两个元素后:%@",NSCollectionToString(array));
        [array insertObject:@"fengkuang",atIndex:2];
        NSLog(@"在索引为2处插入一个元素后:%@",NSCollectionToString(array));
        [array insertObjcets:[NSArray arrayWithObjects:@"ad",@"sf",nil] atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(3,2)]];
        NSLog(@"插入多个元素后:%@",NSCollectionToString(array));
        [array removeLastObject];
        NSLog(@"删除最后一个元素后:%@",NSCollectionToString(array));
        [array removeObjectAtIndex:5];
        NSLog(@"删除索引为5处的元素后:%@",NSCollectionToString(array));
        [array removeObjectsInRange:NSMakeRange(2,3)];
        NSLog(@"删除索引为2-5处的元素后:%@",NSCollectionToString(array));
        [array replaceObjectsAtIndex:2 withObject:@"ads"];
        NSLog(@"替换索引为2处的元素后:%@",NSCollectionTostring(arr));
        
    }
    return 0;
}

分别展示addXxx、removeXxx、replaceXxx、方法进行增删改

集合(NSset和NSMutableSet)

回顾:NSset类似于罐子,将所有元素扔进罐子中。集合里的多个对象之间没有明显顺序,且集合不允许包含相同元素。

如果试图把两个相同元素放在同一个NSSet集合中,则会保留一个元素。

NSSet的功能和用法

NSSet按照Hash算法来储存集合中的元素,因此具有很好的存取和查找性能。

与NSArray相比,最大的区别是元素没有索引。

二者的相同点

  • 都可通过count方法获取集合元素的数量。
  • 都可通过快速枚举来遍历集合元素。
  • 都可通过objectEnumerator方法获取NSEnumerator枚举器对集合元素进行遍历。由于 NSSet集合本身就是无序的,因此,提供反向迭代器没有意义。
  • 都提供了makeObjectsPerformSelector:、makeObjectsPerformSelector:withObject:方法对集合元素整体调用某个方法,以及enumerateObjectsUsingBlock:、enumerateObjectsWithOptions: usingBlock:对集合整体或部分元素迭代执行代码块。
  • 都提供了valueForKey:和setValue:forKey:方法对集合元素整体进行KVC编程。
  • 都提供了集合的所有元素和部分元素进行KVO编程的方法。

下面单独介绍NSSet集合
首先是创建,以set开头为类方法。

  • setByAddingObject::向集合中添加一个新元素,返回添加元素后的新集合。
  • setByAddingObjectsFromSet::使用NSSet集合向集合中添加多个新元素,返回添加元素后的新集合。
  • setByAddingObjectsFromArray::使用NSArray集合向集合中添加多个新元素,返回添加元素后的新集合。
  • allObjects:返回该集合中所有元素组成的NSArray。
  • anyObject:返回该集合中的某个元素。该方法返回的元素是不确定的,但该方法并不保证随机返回集合元素

然后是对集合的访问,遍历,和筛选方法:

  • containsObject::判断集合是否包含指定元素。
  • member::判断该集合是否包含与该参数相等的元素,如果包含,则返回相等的元素:否则返回nil。
  • objectsPassingTest::需要传入一个代码块对集合元素进行过滤,满足该代码块条件的集合元素被保留下来并组成一个新的NSSet集合作为返回值。
  • objectsWithOptions:passingTest::与前一个方法的功能基本相似,只是可以额外地传入一个NSEnumerationOptions迭代选项参数。

NSSet判断集合元素重复的标准

当NSSet集合中存入一个元素后,NSSet会调用该对象的Hash方法来得到该对象的HashCode的值,然后根据HashCode的值决定该对象中底层Hash表中的位置。
如果HashCode相同,接下来就会通过isEqual:方法来判断两个元素是否相等,如果两个元素通过isEqual:方法比较返回NO,则认为不相等,存放在底层Hash表的同一位置,并形成链。如果它们通过isEqual:比较返回YES,则认为两元素相同,不添加。
简而言之,判断相同的标准为:

  1. 两个对象通过isEqual:方法比较返回YES
  2. 两个对象的hash方法返回值也相等。

重写Hash方法的基本规则:

  1. 程序运行过程中,同一个对象多次调用Hash应该返回相同的值
  2. 当两个对象通过isEqual:方法比较返回YES时,两个对象的Hash应返回相等的值
  3. 对象中作为isEqual:比较标准的实例变量,都应该用来计算HashCode值

步骤:

  1. 把对象内每个有意义的实例变量计算出一个int类型的HashCode值
  2. 用第一步计算出来的多个HashCode组合计算出一个HashCode值。为了防止直接相加偶尔相等,可以通过为各实例变量的HashCode值乘任意一个质数后再相加。
return [f1 hash] * 31 + [f2 hash];

有序集合(NSOrderedSet与NSMutableOrderedSet)

这两集合既有NSSet集合的特征,也具有NSArray类似的功能。

  • 不允许元素重复,与NSSet集合相同
  • 可以保持元素的添加顺序,且每个元素都有索引,可以根据索引来操作元素。与NSArray功能相似。

字典!(NSDictionary) 和 NSMutableDictionary

NSDictionary用于保存具有映射关系的数据,因此NSDictionary保存着两组值,一组用于保存NSDictionary里的key,一组用于保存NSDictionary里的value。

注意:key和value可以是任何引用类型的数据,Map的key不允许重复。

key和value之间存在单向的一对一关系,即通过key总能找到唯一、确定的value。

在这里插入图片描述

NSDictionary的功能和用法

NSDictionary超多超多的常见方法:

创建NSDictionary对象方法:

  • dictionary:创建一个不包含任何key-value对的NSDictionary。
  • dictionaryWithContentsOfFile:/initWithContentsOfFile::读取指定文件的内容,使用指定的文件内容来初始化NSDictionary。该文件通常是由NSDictionary输出生成的。
  • dictionaryWithDictionary:/initWithDictionary::使用已有的NSDictionary包含的 key-value对来初始化NSDictionary 对象。
  • dictionaryWithObject:forKey::使用单个key-value对来创建NSDictionary对象。
  • dictionaryWithObjects:forKeys:/initWithObjects:forKeys::使用两个NSArray分别指定 key、value集合,可以创建包含多个key-value对的NSDictionary。
    dictionaryWithObjectsAndKeys:/initWithObjectsAndKeys::调用该方法时,需要按 value1,key1,value2,key2,…,nil 的格式传入多个key-value对。
  • 除此之外,还可使用如下简化语法来创建NSDictionary对象:@{keyl: valuel,key2: value2, …}

访问该集合所包含的key或者value方法:

  • count:该方法返回该NSDictionary所包含的key-value对的数量。

  • allKeys: 该方法返回该NSDictionary所包含的全部 key。

  • allKeysForObject::该方法返回指定value对应的全部 key。

  • allValues:该方法返回该NSDictionary所包含的全部value。

  • objectForKey::该方法获取该NSDictionary中指定key对应的value。

  • objectForKeyedSubscript::通过该方法的支持,允许NSDictionary通过下标法来获取指定key 对应的value。

  • valueForKey::该方法获取该NSDictionary中指定key对应的value。

  • keyEnumerator:该方法返回用于遍历该NSDictionary所有key的NSEnumerator 对象。

  • objectEnumerator:该方法返回用于遍历该NSDictionary所有value的NSEnumerator对象。

  • enumerateKeysAndObjectsUsingBlock::使用指定的代码块来迭代执行该集合中所有的 key-value 对。

  • enumerateKeysAndObjectsWithOptions:usingBlock::使用指定的代码块来迭代执行该集合中所有的key-value对。该方法可以传入一个额外的NSEnumerationOptions参数。

  • writeToFile:atomically::将该NSDictionary对象的数据写入指定文件。

够多吧,来看点重点

看之前,先定义一个print方法,用于便捷打印key-value对的情况。

print函数优化输出
#import <Foundation/Foundation.h>
@interface NSDictionary (print)
- (void) print;
@end
    
 @import "NSDictionary + print.h"
 @implementation NSDictionary (print)
- (void) print
{
   NSMutableString *result = [NSMutableString stringWithString:@"{"];
   for (id key in self)
   {
       [result appendString: [key description]];
       [result appendString:@"="];
       [result appendString: [self[key] description]];
       [result appendString:@","];
   }
   NSUInteger len = [result length];
   [result deleteCharactersInRange:NSMakeRange(len - 2, 2)];
   [result appendString:@"}"];
   NSLog(@"%@",result);
}
@end

是不是很熟悉的输出方法,与前面的颇有异曲同工之处。

通过key获取value的方法有两种:

  • 调用NSDictionary的objectForKey:方法
  • 直接使用下标法
[dictionary objectForKey:key];
dictionary[key];//实际上是调用NSDictionary的objectForKeyedSubscript:方法进行访问
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];
       NSLog(@"dict包含%ld个key-value对",[dict count]);
       NSLog(@"dict的所有key为:%@",[dict allKeys]);
       NSLog(@"<FKUser[name=sum,pass=123]>所对应的所有key为:%@",[dict allKeysForObject:[[FKUser alloc] initWithName:@"sun" pass:@"123"]]);
       NSEnumerator *en = [dict objectEnumerator];
       NSObject *value;
       while (value = [en nextObject])
       {
           NSLog(@"%@",value);
       }
       [dict enumerateKeysAndObjectsUsingBlock:
       ^(id key, id value, BOOL *stop) { // ^是块的开始,整个是块。
           NSLog(@"key的值为:%@",key);
           [value say:@"一夜终极狼人杀好玩"];
       }];

上述代码展示了调用NSDictionary的方法来访问key-value的关键代码,如获取key-value对的数量,以及所有的key和遍历它的所有value的枚举器。最后使用enumerateKeysAndObjectsUsingBlock:方法对所有的key-value对迭代执行指定的代码块。

在这里插入图片描述

对NSDictionary的key排序

返回排序完成后的所有key组成的NSArray,有如下方法:

  • keysSortedByValueUsingSelector::根据NSDictionary的所有key指定方法的返回值对key排序;调用value的该方法必须返回NSOrderedDescending(降序),NSOrderedAscending(升序),NSOrderedSame(相等)三个枚举值之一。
  • keysSortedByvalueUsingComparator:该方法使用指定的代码块来遍历key-value对,并根据执行结果(必须返回如上三个枚举值之一)对NSDictionary的所有key进行排序
  • keysSortedByValueWithOptions:usingComparator::与前一个功能相似,只是可以传入一个额外的NSEnumerationOptions参数。
#import "NSDictionary+print.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
	NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                         @"Objective-c",@"one",
                         @"RUby",@"two",
                         @"Python",@"three",
                         @"Perl",@"four",nil];
     [dict print];
     NSArray *keyArr1 = [dict keysSortedByValueUsingSelector:
                        @selector(compare:)];
     NSLog(@"@",keyArr1);
     NSArray *keyArr2 = [dict keysSortedByValueUSingComparator:
                        ^ (id value1, id value2)
                         {
							if([value1 length] > [value2 length])
                            {
                                return NSOrderedDescending;
                            }
                            if([value1 length] > [value2 length])
                            {
                                return NSOrderedAscending;
                            }
                            return NSOrederSame;
                         }];
      NSLog(@"%@", keyArr2);
      [dict writeToFile:@"wenjianrujing" atomically:YES];
    }
    return 0;
}

上述代码分别才用两种方式对NSDictionary的所有key进行排序,其中一个方法是调用compare:方法进行排序----字符串比较大小直接根据字符对应的编码进行。第二段代码则通过调用代码块进行排序,代码块中的规则是根据字符串长度进行排序。

对NSDictionary 的key进行过滤

可以通过如下两个方法对NSDictionary的所有key进行过滤,这些方法执行完成后饭后满足过滤条件的key组成的NSSet。

  • keysOfEntriesPassingTest::使用代码块迭代处理每个kye-value对。该代码必须返回BOOL类型的值,返回YES该key才会被保留。该代码接受三个参数:第一个参数代表正在处理迭代的key,第二个参数代表正在迭代处理的value,第三个参数代表是否还需要继续迭代,如果将第三个参数设置为NO,该方法会立刻停止迭代
- (NSSet<KeyType> *)keysOfEntriesPassingTest:(BOOL (^)(KeyType key, ObjectType obj, BOOL *stop))predicate;

上述代码为方法定义

#import "NSDictionary+print.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
	NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                   		 [NSNumber numberWihtInt:100], @"Objective-C", 
                         [NSNumber numberWihtInt:50], @"Ruby",
                         [NSNumber numberWihtInt:60], @"Python",
                         [NSNumber numberWihtInt:70], @"Perl",nil];
     [dict print];
  	 NSSet *keySet = [dict keysOfEntriesPassingTest:
                     ^ (id key, id value, BOOL* stop)
                      {
                          return (BOOL)([value intValue] > 80);
                      }];
      NSLog(@"%@",keySet);
   
    }
    return 0;
}
  • keysOfEntriesWithOptions:passingTest::基本与上述相似,但可以额外传入一个附加的NSEnumerationOptions参数
- (NSSet<KeyType> *)keysOfEntriesWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL (^)(KeyType key, ObjectType obj, BOOL *stop))predicate;

上图的为方法定义。可以传入NSEnumerationOptions参数,实现并发或者反向枚举。

  • NSEnumerationConcurrent: 并发枚举。允许在多线程环境中并发地遍历集合,提高性能。
  • NSEnumerationReverse: 反向枚举。按照与正常顺序相反的顺序遍历集合。
NSDictionary *dict = @{@"A": @1, @"B": @2, @"C": @3, @"D": @4, @"E": @5};
NSSet *keys = [dict keysOfEntriesWithOptions:NSEnumerationReverse passingTest:^ BOOL(id key, id obj, BOOL *stop) {
    return [obj intValue] % 2 == 0; // 返回值为偶数的键,但是按照反向顺序遍历
    NSLog(@"满足条件的键为:%@", keys);
}];

使用自定义类作为NSDictionary的key

前面的例子都是使用NSSring作为NSDictionary的key,但是我们可以用自定义类作为NSDictionary的key,需满足如下要求

  • 该自定义类正确重写过isEqual:和Hash方法。要求为:当两个对象通过isEqual:方法判断相同时,两个对象的Hash方法返回值也相同。
  • 该自定义类必须实现了copyWithZone:方法,该方法最好返回对象不可变副本。使用不可变副本是为了防止key索引被破坏,从而导致NSDictionary的完整性被破魂
- (id) copyWithZone:(NSZone *)zone
{
	NSLog(@"---正在copy---");
    FKUser* newUSer = [[[self class] allocWithZone:zone] init];
    newUser->name = name;
    newUser->pass = passs;
    return newUser;
}


#import "NSDictionary+print.h"
#import "FkUser.h"
int main(int argc, const char * argv[]) { 
    @autoreleasepool {
        FKUser *u1 = [[FKUser alloc] initWithName:@"bai" pass:@"354"];
        NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                             @"one", [[FKUser alloc] initWithName:@"sun" pass:@"123"],
                             @"two",u1,
                             @"three", [[FKUser alloc] initWithName:@"sun" pass:@"123"],
                             @"four", [[FKUser alloc] initWithName:@"tang" pass:@"178"],
                        @"five", [[FKUser alloc] initWithName:@"niu" pass:@"155"],nil];
        [dict print];

    }
    return 0;
}

运行结果:
在这里插入图片描述

NSMutableDictionary的功能和用法

开始变啦,与NSArray与NSMutableArray相似,NSMutableDictionary增加了增删改的方法。

  • setObject:forKey::设置一个key-value对。如果NSDictionary中没有包含与该key相同的 key-value 对,那么NSDictionary将会新增一个key-value对;否则该key-value对将会覆盖已有的key-value对。
  • setObject:forKeyedSubscript::通过该方法的支持,允许程序通过下标法来设置key-value对。
  • addEntriesFromDictionary::将另一个NSDictionary中所有的key-value对复制到当前 NSDictionary 中。
  • setDictionary::用另一个NSDictionary中所有的key-value对替换当前NSDictionary 中的 key-value 对。
  • removeObjectForKey::根据key来删除 key-value 对。 removeAllObjects:清空该NSDictionary。
  • removeObjectsForKeys::使用多个key组成的NSArray作为参数,同时删除多个key对应的key-value对。
#import <Foundation/Foundation.h>
#import "NSDictionary+print.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:89],@"疯狂Android讲义", nil];
        dict[@"疯狂Android讲义"] = [NSNumber numberWithInt:99];
        [dict print];
        NSLog(@"--再次添加key-value对--");
        dict[@"疯狂iOS讲义"] = [NSNumber numberWithInt:69];
        [dict print];
        NSDictionary *dict2 = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:79],@"疯狂Ajax讲义",[NSNumber numberWithInt:89], @"Struts 2.x权威指南", nil];
        [dict addEntriesFromDictionary:dict2];
        [dict print];
        [dict removeObjectForKey:@"Struts 2.x权威指南"];
        [dict print];
    }
    return 0;
}

上述代码简单展示了常用的方法来动态改变NSMutableDictionary中的key-value对。
在这里插入图片描述


  • 20
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值