OC--NSDictionary字典

NSDictionary:字典,是一种以Key:Value的形式存储数据的形式。简单来说就是使用一个标识字符串来标志一个值。在使用的时候,我们就可以直接使用标识。可以理解为一堆变量的集合。既然是集合,那么就有集合的无序性。这个和数组不同。

键(key):可以为任何对象(但通常都是NSString类型的字符串),必须是单值。

值(value):可以是任何对象,不能是nil。

对于字典的使用,通常是使用键来读取查询相对应的值。


创建一个字典对象的方法有很多,在官方的NSDictionary类中有一下方法可以用来创建一个字典对象:

+ (instancetype)dictionary;

+ (instancetype)dictionaryWithObject:(ObjectType)object forKey:(KeyType <NSCopying>)key;

#if TARGET_OS_WIN32

+ (instancetype)dictionaryWithObjects:(const ObjectType [])objects forKeys:(const KeyType [])keys count:(NSUInteger)cnt;

#else

+ (instancetype)dictionaryWithObjects:(const ObjectType [])objects forKeys:(const KeyType <NSCopying> [])keys count:(NSUInteger)cnt;

#endif


+ (instancetype)dictionaryWithObjectsAndKeys:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION NS_SWIFT_UNAVAILABLE("Use dictionary literals instead");


+ (instancetype)dictionaryWithDictionary:(NSDictionary<KeyType, ObjectType> *)dict;

+ (instancetype)dictionaryWithObjects:(NSArray<ObjectType> *)objects forKeys:(NSArray<KeyType <NSCopying>> *)keys;


- (instancetype)initWithObjectsAndKeys:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;

- (instancetype)initWithDictionary:(NSDictionary<KeyType, ObjectType> *)otherDictionary;

- (instancetype)initWithDictionary:(NSDictionary<KeyType, ObjectType> *)otherDictionary copyItems:(BOOL)flag;

- (instancetype)initWithObjects:(NSArray<ObjectType> *)objects forKeys:(NSArray<KeyType <NSCopying>> *)keys;


+ (nullable NSDictionary<KeyType, ObjectType> *)dictionaryWithContentsOfFile:(NSString *)path;

+ (nullable NSDictionary<KeyType, ObjectType> *)dictionaryWithContentsOfURL:(NSURL *)url;

- (nullable NSDictionary<KeyType, ObjectType> *)initWithContentsOfFile:(NSString *)path;

- (nullable NSDictionary<KeyType, ObjectType> *)initWithContentsOfURL:(NSURL *)url;

在我们实际的使用中,常用的方法有:

创建一个字典对象

+ (instancetype)dictionary;

创建一个字典对象,并使用K:V形式初始化数据

+ (instancetype)dictionaryWithObject:(ObjectType)object forKey:(KeyType <NSCopying>)key;

创建一个字典对象,并使用另一个字典初始化数据

+ (instancetype)dictionaryWithDictionary:(NSDictionary<KeyType, ObjectType> *)dict;

创建一个字典对象,使用K数组和V数组初始化数据

+ (instancetype)dictionaryWithObjects:(NSArray<ObjectType> *)objects forKeys:(NSArray<KeyType <NSCopying>> *)keys;

创建一个字典对象,并使用K:V形式初始化数据

- (instancetype)initWithObjectsAndKeys:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;

创建一个字典对象,并使用另一个字典初始化数据

- (instancetype)initWithDictionary:(NSDictionary<KeyType, ObjectType> *)otherDictionary;

上面的创建方法其实大体都是一样的。区别在于调用方式和初始化方式的不同。下面看看字典有哪些常用属性和方法


字典的常用属性和方法:

属性:

字典词条数量

@property (readonly) NSUInteger count;

字典中所有的键Key

@property (readonly, copy) NSArray<KeyType> *allKeys;

字典中所有的值Value

@property (readonly, copy) NSArray<ObjectType> *allValues;

字典内容描述的字符串,plist格式

@property (readonly, copy) NSString *description;

.string格式字典内容描述的字符串,

@property (readonly, copy) NSString *descriptionInStringsFileFormat;

代码示例:

//创建字典对象,初始化

        NSDictionary *dic = [NSDictionary dictionaryWithObjects:@[@"jeck", @"20", @"boy"] forKeys:@[@"name", @"age", @"sex"]];

        //打印字典条目数量(长度)

        NSLog(@"字典条目数量:%lu", dic.count);

        //打印字典所有的key

        NSLog(@"字典所有的key:%@", dic.allKeys);

        //打印字典所有的value

        NSLog(@"字典所有的value:%@", dic.allValues);

        //打印字典描述,plist格式

        NSLog(@"plist格式描述:%@", dic.description);

        //打印.string格式字典内容描述

        NSLog(@".string格式字典内容描述:%@", dic.descriptionInStringsFileFormat);

打印结果:

2017-03-21 10:21:14.071 OCdemo[698:35153] 字典条目数量:3

2017-03-21 10:21:14.072 OCdemo[698:35153] 字典所有的key:(

    name,

    age,

    sex

)

2017-03-21 10:21:14.072 OCdemo[698:35153] 字典所有的value:(

    jeck,

    20,

    boy

)

2017-03-21 10:21:14.072 OCdemo[698:35153] plist格式描述:{

    age = 20;

    name = jeck;

    sex = boy;

}

2017-03-21 10:21:14.072 OCdemo[698:35153] .string格式字典内容描述:"name" = "jeck";

"age" = "20";

"sex" = "boy";

Program ended with exit code: 0

在上面的打印结果中, description和descriptionInStringsFileFormat的区别只是description是一个字典格式的数据输出,descriptionInStringsFileFormat是一个字符串格式的数据输出。


字典数据的读取

之所以会有字典这种数据形式,就是为了使用key去读取和查询value。既然如此,那么字典数据的读取就很简单了,就是使用字典的key就可以获取到value。

这就是读取字典中value的方法

- (nullable ObjectType)objectForKey:(KeyType)aKey;

代码示例:

NSDictionary *dic = [NSDictionary dictionaryWithObjects:@[@"jeck", @"20", @"boy"] forKeys:@[@"name", @"age", @"sex"]];

        //读取字典中存储的姓名

        NSString *nameString = [dic objectForKey:@"name"];

        //打印读取结果

        NSLog(@"姓名:%@", nameString);

打印结果:

2017-03-21 10:27:21.206 OCdemo[709:37052] 姓名:jeck

Program ended with exit code: 0

在上面的代码中,会有一个小问题,那就是当在取值的时候,objectForKey:方法后面传入的参数是一个字符串,这样的形式使得在开发中,可以根据自己或者团队统一定义命名方式存取数据,很便于管理。但是也有一些问题,那就是字符串在Xcode中是不会被检查报错的,即使我们写错了key,系统也不回给报出错误,所以,在这里一定要特别小心,不要出现一些这样的错误。


字典的常用操作

枚举遍历字典中的key或者value

返回一个可以快速访问字典中所有关键字(key)的快速枚举器。

- (NSEnumerator<KeyType> *)keyEnumerator;

返回一个可以快速访问字典中所有值(value)的快速枚举器。

- (NSEnumerator<ObjectType> *)objectEnumerator;

返回字典中所有值anObject对应的key。

- (NSArray<KeyType> *)allKeysForObject:(ObjectType)anObject;

代码示例:

//创建字典对象,初始化

        NSDictionary *dic = [NSDictionary dictionaryWithObjects:@[@"jeck"@"20"@"boy"forKeys:@[@"name"@"age"@"sex"]];

        //创建关键字遍历枚举器

        NSEnumerator *keyEnumera = [dic keyEnumerator];

        //指向下一个对象

        id key = [keyEnumera nextObject];

        //遍历

        while (key) {

            NSLog(@"keyEnumera :%@", [dic objectForKey:key]);

            key = [keyEnumera nextObject];

        }

        NSLog(@"---------------分割线--------------");

        //创建值遍历枚举器

        NSEnumerator *valueEnumer = [dic objectEnumerator];

        //指向下一个对象

        id value = [valueEnumer nextObject];

        //遍历

        while (value) {

            NSLog(@"valueEnumer :%@", [dic allKeysForObject:value]);

            value = [valueEnumer nextObject];

        }

打印结果:

2017-03-21 10:48:29.190 OCdemo[794:45990] keyEnumera :jeck

2017-03-21 10:48:29.191 OCdemo[794:45990] keyEnumera :20

2017-03-21 10:48:29.192 OCdemo[794:45990] keyEnumera :boy

2017-03-21 10:48:29.192 OCdemo[794:45990] ---------------分割线--------------

2017-03-21 10:48:29.192 OCdemo[794:45990] valueEnumer :(

    name

)

2017-03-21 10:48:29.192 OCdemo[794:45990] valueEnumer :(

    age

)

2017-03-21 10:48:29.193 OCdemo[794:45990] valueEnumer :(

    sex

)

Program ended with exit code: 0

从上面的打印结果来看,使用key遍历打印的都是一个个字符串值,而使用value遍历打印的是一个个的数组,这是因为没有一个方法可以像objectForKey:一样很方便通过值去获取到key,所以这里算是‘作弊’的形式,使用 allKeysForObject:方法展示一下value对应的key。这里需要注意,当在这个字典里有多个key对应相同的值的时候,这样打印就不是这样了。看下面的代码:

NSDictionary *dic = [NSDictionary dictionaryWithObjects:@[@"jeck", @"20", @"boy", @"20"] forKeys:@[@"name", @"age", @"sex", @"number"]];

        //创建值遍历枚举器

        NSEnumerator *valueEnumer = [dic objectEnumerator];

        //指向下一个对象

        id value = [valueEnumer nextObject];

        //遍历

        while (value) {

            NSLog(@"valueEnumer :%@", [dic allKeysForObject:value]);

            value = [valueEnumer nextObject];

        }

打印结果:

2017-03-21 10:53:59.131 OCdemo[834:48011] valueEnumer :(

    age,

    number

)

2017-03-21 10:53:59.132 OCdemo[834:48011] valueEnumer :(

    sex

)

2017-03-21 10:53:59.132 OCdemo[834:48011] valueEnumer :(

    age,

    number

)

2017-03-21 10:53:59.132 OCdemo[834:48011] valueEnumer :(

    name

)

Program ended with exit code: 0

看到结果的时候就会发现 objectEnumerator是遍历所有的value,而allKeysForObject:是获取所有的value对应的key,在上面的字典中,20 对应的key有name和number。所以才会这样额打印输出。


字典的比较

比较两个字典是否相同

- (BOOL)isEqualToDictionary:(NSDictionary<KeyType, ObjectType> *)otherDictionary;

代码示例:

NSDictionary *dic = [NSDictionary dictionaryWithObjects:@[@"jeck", @"20", @"boy", @"20"] forKeys:@[@"name", @"age", @"sex", @"number"]];

        NSDictionary *dic1 = [NSDictionary dictionaryWithObjects:@[@"jeck", @"20", @"boy", @"20"] forKeys:@[@"name", @"age", @"sex", @"number"]];

        //使用isEqualToDictionary:比较

        if ([dic isEqualToDictionary:dic1]) {

            NSLog(@"相同");

        }else{

            NSLog(@"不同");

        }

        //使用==比较

        if (dic1 == dic) {

            NSLog(@"相同");

        }else{

            NSLog(@"不同");

        }

        

        //打印地址

        NSLog(@"dic的地址:%p,dic1的地址:%p", &dic, &dic1);

打印结果:

2017-03-21 11:01:30.400 OCdemo[876:50380] 相同

2017-03-21 11:01:30.401 OCdemo[876:50380] 不同

2017-03-21 11:01:30.401 OCdemo[876:50380] dic的地址:0x7fff5fbff770,dic1的地址:0x7fff5fbff768

Program ended with exit code: 0

从上面的打印结果可以看出,isEqualToDictionary:方法比较的是两个字典的key和value是否完全相同,因为字典的无序性,即使顺序不同也只要对应的key:value相同,那么这两个字典也是相同的。而使用‘==’进行判断时不仅仅是key、value还有地址。==表示两个对象完全一样,地址不同就是两个对象,当然不可能完全一样。


字典遍历

上面已经说了枚举遍历字典的方法,下面再来说几个遍历字典的方法:

1、使用allValues方法获取字典中所有的值进行数组遍历

NSDictionary *dic = [NSDictionary dictionaryWithObjects:@[@"jeck", @"20", @"boy", @"20"] forKeys:@[@"name", @"age", @"sex", @"number"]];

        //获取字典中所有的value

        NSArray *valuesArray = [dic allValues];

        //for循环遍历

        for (int i = 0; i < valuesArray.count; i++) {

            NSLog(@"%@", valuesArray[i]);

        }

        NSLog(@"--------------分割线------------");

        //for-in循环遍历

        for (NSDictionary *dic in valuesArray) {

            NSLog(@"%@",dic);

        }

打印结果:

2017-03-21 11:15:03.533 OCdemo[927:55325] 20

2017-03-21 11:15:03.534 OCdemo[927:55325] boy

2017-03-21 11:15:03.534 OCdemo[927:55325] 20

2017-03-21 11:15:03.534 OCdemo[927:55325] jeck

2017-03-21 11:15:03.534 OCdemo[927:55325] --------------分割线------------

2017-03-21 11:15:03.535 OCdemo[927:55325] 20

2017-03-21 11:15:03.535 OCdemo[927:55325] boy

2017-03-21 11:15:03.535 OCdemo[927:55325] 20

2017-03-21 11:15:03.535 OCdemo[927:55325] jeck

Program ended with exit code: 0


2、使用allKeys方法获取所有的key,再使用objectForKey:方法获取对应的value,进行循环遍历

NSDictionary *dic = [NSDictionary dictionaryWithObjects:@[@"jeck", @"20", @"boy", @"20"] forKeys:@[@"name", @"age", @"sex", @"number"]];

        //获取字典中所有的key

        NSArray *keysArray = [dic allKeys];

        //for循环遍历

        for (int i = 0; i < keysArray.count; i++) {

            NSLog(@"%@", [dic objectForKey:keysArray[i]]);

        }

        NSLog(@"--------------分割线-------------");

        //for-in循环遍历

        for (NSString *keyString in keysArray) {

            NSLog(@"%@", [dic objectForKey:keyString]);

        }

打印结果:

2017-03-21 11:18:33.933 OCdemo[950:56650] 20

2017-03-21 11:18:33.934 OCdemo[950:56650] boy

2017-03-21 11:18:33.934 OCdemo[950:56650] 20

2017-03-21 11:18:33.934 OCdemo[950:56650] jeck

2017-03-21 11:18:33.934 OCdemo[950:56650] --------------分割线-------------

2017-03-21 11:18:33.934 OCdemo[950:56650] 20

2017-03-21 11:18:33.934 OCdemo[950:56650] boy

2017-03-21 11:18:33.934 OCdemo[950:56650] 20

2017-03-21 11:18:33.934 OCdemo[950:56650] jeck

Program ended with exit code: 0


前面说到字典是无序的,那么我们在遍历的时候,所得到的值也就是无序的,要想实现有序遍历该如何呢?

3、有序遍历

NSDictionary *dic = [NSDictionary dictionaryWithObjects:@[@"jeck", @"10", @"boy", @"20"] forKeys:@[@"name", @"age", @"sex", @"number"]];

        //获取字典中所有的key

        NSArray *keysArray = [dic allKeys];

        //key数组进行排序

        keysArray = [keysArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2){

            NSComparisonResult result = [obj1 compare:obj2];

            return result==NSOrderedDescending;

        }];

        //for循环遍历

        for (int i = 0; i < keysArray.count; i++) {

            NSLog(@"%@", [dic objectForKey:keysArray[i]]);

        }

        NSLog(@"--------------分割线-------------");

        //for-in循环遍历

        for (NSString *keyString in keysArray) {

            NSLog(@"%@", [dic objectForKey:keyString]);

        }

打印结果:

2017-03-21 11:22:41.922 OCdemo[971:58569] 10

2017-03-21 11:22:41.923 OCdemo[971:58569] jeck

2017-03-21 11:22:41.924 OCdemo[971:58569] 20

2017-03-21 11:22:41.924 OCdemo[971:58569] boy

2017-03-21 11:22:41.924 OCdemo[971:58569] --------------分割线-------------

2017-03-21 11:22:41.924 OCdemo[971:58569] 10

2017-03-21 11:22:41.925 OCdemo[971:58569] jeck

2017-03-21 11:22:41.925 OCdemo[971:58569] 20

2017-03-21 11:22:41.925 OCdemo[971:58569] boy

Program ended with exit code: 0

打印来看,age对应的10最先被打印出来,因为在排序中age是被排带最前面。


到这里,不可变字典的一些常用操作就说完了。下一篇是可变字典(NSMutableDictionary)的操作,与字符串和数组一样,可变字典是继承自NSDictionary的,所以,这篇文章中说到的属性和方法都是适用的。

猜你喜欢

转载自blog.csdn.net/m0_37681833/article/details/64438313