您的位置:首页 > 移动开发 > IOS开发

【IOS 开发学习总结-OC-31】★★OC之foundation 框架——字典(NSDictionary 与 NSMutableDictionary)

2015-10-05 08:58 741 查看
NSDictionary用于保存具有映射关系的数据。NSDictionary集合保存了2组值——一组存 key, 一组存 value。

value与 key 都可以是任何引用类型的数据。Map 的 key 不允许重复。value与 key存在但相向一对一的关系。一个 key 对应唯一的一个 value.

NSDictionary的功能与用法

NSDictionary的创建同样有类方法和实例方法。以 dictionary 开头的是类方法,以 init 开头的是实例方法。

创建NSDictionary对象的几类常见方法:

创建NSDictionary对象的几类常见方法:

1.
dictionary:
——创建一个不包含任何 key-value 对的NSDictionary

2.
dictionaryWithContentsOfFile:/initWithContentsOfFile:
——读取指定文件的内容来初始化NSDictionary(该文件通常是由NSDictionary自己输出生成)

3.
dictionaryWithDictionary:/initWithDictionary:
——用已有的包含 key-value 对 来初始化NSDictionary对象

4.
dictionaryWithObject: forKey:
——用单个key-value 对 创建NSDictionary对象

5.
dictionaryWithObjects:<#(nonnull NSArray *)#> forKeys:<#(nonnull NSArray<id<NSCopying>> *)#>
——使用2个NSArray分别指定 key,value 集合,可以创建多组key-value 对的NSDictionary。

6.
dictionaryWithObjectsAndKeys:
——按 value1,key1,value2,key2,……nil 的格式传入多个键值对。

得到NSDictionary对象后,如何访问该集合包含的 key 或 value 呢?

得到NSDictionary对象后,如何访问该集合包含的 key 或 value 呢?

1.
count
:——返回NSDictionary包含的键值对的数量

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.
enumerateKeysAndObjectsUsingBlock:
——使用代码块,来迭代执行该集合中所有的 键值对。

11.
enumerateKeysAndObjectsWithOptions:<#(NSEnumerationOptions)#> usingBlock:
————使用代码块,来迭代执行该集合中所有的 键值对,该方法可以传入一个额外得到 option参数

12.
writeToFile:<#(nonnull NSString *)#> atomically:<#(BOOL)#>
——将该字典对象的数据写入指定文件。

示例代码:

FKUser.h

#import <Foundation/Foundation.h>

@interface FKUser : NSObject
@property (nonatomic , copy) NSString* name;
@property (nonatomic , copy) NSString* pass;
- (id) initWithName:(NSString*) aName
pass:(NSString*) aPass;
- (void) say:(NSString*) content;
@end


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);
}
// 会重写isEqual:方法,重写该方法的比较标准是,
// 如果两个FKUser的name、pass相等,即可认为两个FKUser相等。
- (BOOL) isEqual:(id)other
{
if(self == other)
{
return YES;
}
if([other class] == FKUser.class)
{
FKUser* target = (FKUser*)other;
return [self.name isEqualToString:target.name]
&& [self.pass isEqualToString:target.pass];
}
return NO;
}
// 会重写isEqual:方法,重写该方法的比较标准是,
// 如果两个FKUser的name、pass相等,即可认为两个FKUser相等。
- (NSUInteger) hash
{
NSUInteger nameHash = name == nil ? 0 : [name hash];
NSUInteger passHash = pass == nil ? 0 : [pass hash];
return nameHash * 31 + passHash;

}
// 重写description方法,可以直接看到FKUser对象的状态
- (NSString*) description
{
return [NSString stringWithFormat:
@"<FKUser[name=%@, pass=%@]>"
, self.name , self.pass];
}
- (id)copyWithZone:(NSZone *)zone
{
NSLog(@"--正在复制--");
// 复制一个对象
FKUser* newUser = [[[self class] allocWithZone:zone] init];
// 将被复制对象的实变量的值赋给新对象的实例变量
newUser->name = name;
newUser->pass = pass;
return newUser;
}
@end


NSDictionary+print.h

#import <Foundation/Foundation.h>

@interface NSDictionary (print)
- (void) print;
@end


NSDictionary+print.m

#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);
}
@end


通过 key 来获取 value 有2种语法(2种方法功能相同):

dictionary objectForKey:key];
(objectForKey方法)与
dictionary[key];
(下标法)是等价的。推荐用后者(更简单易用)。

NSDictionaryTest.m

//  Created by yeeku on 2013-4-22.
//  Copyright (c) 2013年 crazyit.org. All rights reserved.

#import <Foundation/Foundation.h>
#import "NSDictionary+print.h"
#import "FKUser.h"

int main(int argc , char * argv[])
{
@autoreleasepool{

// 直接使用多个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];
NSLog(@"dict包含%ld个key-value对", [dict count]);
NSLog(@"dict的所有key为:%@" , [dict allKeys]);
NSLog(@"<FKUser[name=sun,pass=123]>对应的所有key为:%@"
, [dict allKeysForObject:
[[FKUser alloc] initWithName:@"sun"
pass:@"123"]]);
// 获取遍历dict所有value的枚举器
NSEnumerator* en = [dict objectEnumerator];
NSObject* value;
// 使用枚举器来遍历dict中所有value。
while(value = [en nextObject])
{
NSLog(@"%@" , value);
}
// 使用指定代码块来迭代执行该集合中所有key-value对。
[dict enumerateKeysAndObjectsUsingBlock:
// 该集合包含多个key-value对,下面代码块就执行多少次
^(id key, id value, BOOL *stop)
{
NSLog(@"key的值为:%@" , key);
[value say:@"疯狂iOS讲义"];
}];
}
}


编译运行结果:

2015-10-04 11:54:25.892 923[1614:62069] {one=<FKUser[name=sun, pass=123]>, five=<FKUser[name=niu, pass=155]>, three=<FKUser[name=sun, pass=123]>, two=<FKUser[name=bai, pass=345]>, four=<FKUser[name=tang, pass=178]>}
2015-10-04 11:54:25.901 923[1614:62069] dict包含5个key-value对
2015-10-04 11:54:25.901 923[1614:62069] dict的所有key为:(
one,
five,
three,
two,
four
)
2015-10-04 11:54:25.902 923[1614:62069] <FKUser[name=sun,pass=123]>对应的所有key为:(
one,
three
)
2015-10-04 11:54:25.903 923[1614:62069] <FKUser[name=sun, pass=123]>
2015-10-04 11:54:25.903 923[1614:62069] <FKUser[name=niu, pass=155]>
2015-10-04 11:54:25.904 923[1614:62069] <FKUser[name=sun, pass=123]>
2015-10-04 11:54:25.905 923[1614:62069] <FKUser[name=bai, pass=345]>
2015-10-04 11:54:25.905 923[1614:62069] <FKUser[name=tang, pass=178]>
2015-10-04 11:54:25.906 923[1614:62069] key的值为:one
2015-10-04 11:54:25.906 923[1614:62069] sun说:疯狂iOS讲义
2015-10-04 11:54:25.907 923[1614:62069] key的值为:five
2015-10-04 11:54:25.907 923[1614:62069] niu说:疯狂iOS讲义
2015-10-04 11:54:25.908 923[1614:62069] key的值为:three
2015-10-04 11:54:25.908 923[1614:62069] sun说:疯狂iOS讲义
2015-10-04 11:54:25.908 923[1614:62069] key的值为:two
2015-10-04 11:54:25.909 923[1614:62069] bai说:疯狂iOS讲义
2015-10-04 11:54:25.909 923[1614:62069] key的值为:four
2015-10-04 11:54:25.909 923[1614:62069] tang说:疯狂iOS讲义


对NSDictionary的key 排序

对NSDictionary的key 排序的方法如下(这些方法执行完成后将返回排序完成后的所有 key 组成的 NSArray):

1.
keysSortedByValueUsingSelector:
——根据NSDictionary的所有 value 的指定方法的返回值对 key 排序:调用 value 的该方法必须返回 NSOrderedAscending,NSOrderedDesending,NSOrderedSame三个值之一。

2.
keysSortedByValueUsingComparator:
——使用指定的代码块来遍历键值 对,并根据执行结果(NSOrderedAscending,NSOrderedDesending,NSOrderedSame三个值之一)对NSDictionary的所有 key 进行排序。

3.
keysSortedByValueWithOptions:<#(NSSortOptions)#> usingComparator:
——与上一种方法功能相似,可以传入一个额外的参数。

示例程序(用的是前面的类别文件):

#import <Foundation/Foundation.h>
#import "NSDictionary+print.h"

int main(int argc , char * argv[])
{
@autoreleasepool{
// 直接使用多个value,key的形式创建NSDictionary对象
NSDictionary* dict = [NSDictionary
dictionaryWithObjectsAndKeys:
@"Objective-C" , @"one",
@"Ruby" , @"two",
@"Python" , @"three",
@"Perl" , @"four", nil];
// 打印dict集合的所有元素
[dict print];
// 获取所有直接调用value的compare:方法对所有key进行排序。
// 返回排好序的所有key组成的NSArray。
NSArray* keyArr1 = [dict keysSortedByValueUsingSelector:
@selector(compare:)];
NSLog(@"%@" , keyArr1);
NSArray* keyArr2 = [dict keysSortedByValueUsingComparator:
// 对NSDictionary的value进行比较,字符串越长,即可认为该value越大
^(id value1, id value2)
{
// 下面定义比较大小的标准:字符串越长,即可认为value越大
if([value1 length] > [value2 length])
{
return NSOrderedDescending;
}
if([value1 length] < [value2 length])
{
return NSOrderedAscending;
}
return NSOrderedSame;
}];
NSLog(@"%@" , keyArr2);
// 将NSDictionary的内容输出到指定文件中
[dict writeToFile:@"mydict.txt" atomically:YES];
}
}


编译运行结果:

2015-10-04 21:08:50.294 923[2781:170541] {one=Objective-C, three=Python, two=Ruby, four=Perl}
2015-10-04 21:08:50.296 923[2781:170541] (
one,
four,
three,
two
)
2015-10-04 21:08:50.296 923[2781:170541] (
two,
four,
three,
one
)


对NSDictionary的key 进行过滤

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

NSDictionary提供的过滤方法

NSDictionary提供了如下方法:

1.
keysOfEntriesPassingTest:
——使用代码块迭代处理 NSDictionary的每个键值对。对 键值对进行过滤,该代码块必须返回 BOOL 类型的值。——只有返回 YES 时,key才保留下来。

keysOfEntriesPassingTest:
方法代码块参数说明。方法中的代码块可以接受3个参数:第一个参数代表,正在迭代处理的 key,第二个参数代表正在迭代处理的 value,第三个参数代表是否还需要继续 迭代。——如果第三个参数设置为 NO,该方法会立即停止迭代。

keysOfEntriesWithOptions:<#(NSEnumerationOptions)#> passingTest:
——与上面的方法功能相似,可以额外传入 一个 NSEnumerationOptions 参数。

示例代码:

NSDictionaryFilter.m

#import <Foundation/Foundation.h>
#import "NSDictionary+print.h"

int main(int argc , char * argv[])
{
@autoreleasepool{
// 直接使用多个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];
// 对NSDictionary的所有key进行过滤
NSSet* keySet = [dict keysOfEntriesPassingTest:
// 对NSDictionary的value进行比较,字符串越长,即可认为该value越大
^(id key, id value, BOOL* stop)
{
// 当value的值大于80时返回YES
// 这意味着只有value的值大于80的key才会被保存下来
return (BOOL)([value intValue] > 80);
}];
NSLog(@"%@" , keySet);
}
}


编译运行结果:

2015-10-04 21:28:40.276 923[2860:178721] {Perl=109, Objective-C=89, Python=75, Ruby=69}
2015-10-04 21:28:40.280 923[2860:178721] {(
Perl,
"Objective-C"
)}


使用自定义类作为NSDictionary的 key

如果程序打算使用自定义类作为NSDictionary的 key, 则该自定义类必须满足如下要求:

- 该自定义类正确重写过
isEqual:
hash
方法。正确重写是指当2个对象通过
isEqual:
判断相等时,,2个对象 的 Hash 方法返回值也相等。

- 该自定义 类必须实现了
copyWithZone:
方法。该方法最好能返回对象的不可变副本。——这是出于安全性的考虑,防止 key 被 修改,破坏NSDictionary的完整性。每次添加,总会先调用 key 的 copy 方法复制该对象的不可变副本 ,以此副本作为 NSDictionary的 key。

在FKUser.m 文件中实现
copyWithZone:
方法,并使该FKUser类 实现 NSCopying 协议(建议实现)。

- (id)copyWithZone:(NSZone *)zone
{
NSLog(@"--正在复制--");
// 复制一个对象
FKUser* newUser = [[[self class] allocWithZone:zone] init];
// 将被复制对象的实变量的值赋给新对象的实例变量
newUser->name = name;
newUser->pass = pass;
return newUser;
}
@end


test.m

#import <Foundation/Foundation.h>
#import "NSDictionary+print.h"
#import "FKUser.h"

int main(int argc , char * argv[])
{
@autoreleasepool{
FKUser* u1 = [[FKUser alloc] initWithName:@"bai"
pass:@"345"];
// 直接使用多个value,key的形式创建NSDictionary对象
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];
// 将u1的密码设为nil
u1.pass = nil;
// 由于NSDictionary并未直接使用u1所指向的FKUser作为key,
// 而是先复制了u1所指向对象的副本,然后以该副本作为key。
// 因此程序将可以看到dict的key不会受到任何影响。
[dict print];
}
}


编译运行 结果;

2015-10-04 21:42:18.987 923[2923:184530] --正在复制--
2015-10-04 21:42:18.991 923[2923:184530] --正在复制--
2015-10-04 21:42:18.991 923[2923:184530] --正在复制--
2015-10-04 21:42:18.991 923[2923:184530] --正在复制--
2015-10-04 21:42:18.993 923[2923:184530] {<FKUser[name=bai, pass=345]>=two, <FKUser[name=sun, pass=123]>=one, <FKUser[name=tang, pass=178]>=four, <FKUser[name=niu, pass=155]>=five}s


NSMutableDictionary的功能与用法

创建NSMutableDictionary对象时,可以指定初始 容量。——因为,NSMutableDictionary可以动态添加键值对。

1.
addEntriesFromDictionary:
——将另一个字典中的键值对复制添加到当前字典中

2.
removeObjectForKey:
——根据键删除键值对

3.
setObject:forKey:
——设置一个键值对。

4.
setObject:forKeyedSubscript:
——该 方法 使得程序可以通过下标法

5.
setDictionary
——用另一个字典中所有的键值对替换当前字典中的键值对

6.
removeallObjects:
——清空该字典。

7.
removeObjectsForKeys:
——使用多个 key 组成的 NSArray 作为参数,同时删除多个 key 对应的键值对。

示例代码段 :

int main(int argc , char * argv[])
{
@autoreleasepool{
// 直接使用多个value,key的形式创建NSDictionary对象
NSMutableDictionary* dict = [NSMutableDictionary
dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:89] , @"疯狂Android讲义", nil];
// 使用下标法设置key-value对。
// 由于NSDictionary中已存在该key,
// 因此此处设置的value会覆盖前面的value。
dict[@"疯狂Android讲义"] = [NSNumber numberWithInt:99];
[dict print];
NSLog(@"--再次添加key-value对--");
dict[@"疯狂XML讲义"] = [NSNumber numberWithInt:69];
[dict print];
NSDictionary* dict2 = [NSDictionary
dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:79] , @"疯狂Ajax讲义",
[NSNumber numberWithInt:89] , @"Struts 2.x权威指南"
, nil];
// 将另外一个NSDictionary中的key-value对添加到当前NSDictionary中
[dict addEntriesFromDictionary:dict2];
[dict print];
// 根据key来删除key-value对
[dict removeObjectForKey:@"Struts 2.x权威指南"];
[dict print];
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息