OC
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的,所以,这篇文章中说到的属性和方法都是适用的。