NSHashTable 和 NSMapTable

NSHashTable 和 NSMapTable

前言

在我们的开发之中不知道你是否留意过这两个类?在你的代码中,有没有使用过这两个类?( ps:在我开发的过程中,居然没有用过。)
下面我们就来看看这两个类是用来干什么的。

NSHashTable

可能在今天的 ARC 的内存管理下,我们不太注重对于一个对象的内存管理,不太注重是不是会产生强引用,所以对于 NSHashTable 这个类不太关注,至少在我的开发过程中,没有去使用这个类。

NSHashTable 效仿了 NSSet(NSMutableSet) ,但是提供了比 NSSet 更多的操作选择。特别是在弱引用的支持上,NSHashTable 在对象以及内存处理上更加灵活。

特性

1. NSHashTable 是可变的,它没有不可变版本。
2. 它可以持有元素的弱引用,而且对象被销毁之后能正确的将其移除。而这一点在 NSSet 是做不到的。
3. 它的成员可以在添加时被拷贝。
4. 它的成员可以使用指针来标识是否相等及做 hash 检测
5. 它可以包含任意指针,其成员没有限制为对象。我们可以配置一个 NSHashTable 实例来操作任意的指针,而不仅仅是对象。

初始化 NSHashTable 时,我们可以设置一个初始选项,这个选项确定了 NSHashTable 对象后面所有的行为。这个选项是有 NSHashTableOptions 枚举来定义的,枚举类型如下:

1
2
3
4
5
6
7
8
9
10
11
12
// 默认行为,强引用集合中的对象,等同于 NSSet 
NSHashTableStrongMemory = 0,

// 在将对象添加到集合之前,会拷贝对象
NSHashTableCopyIn = NSPointerFunctionsCopyIn,

// 使用移位指针 (shifted pointer) 来做 hash 检测及确定两个对象是否相等;
// 同时使用 description 方法来做描述字符串
NSHashTableObjectPointerPersonality = NSPointerFunctionsObjectPointerPersonality,

// 弱引用集合中的对象,且在对象被释放后,会被正确的移除。
NSHashTableWeakMemory = NSPointerFunctionsWeakMemory

示例

我们来看一下,关于弱引用的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#import "ViewController.h"

@interface ViewController () {
NSHashTable *_hashTable;
}
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

[self test];
NSLog(@"调用之后的 hashTable:%@", _hashTable);
}

- (void)test {
if (!_hashTable) {
_hashTable = [NSHashTable weakObjectsHashTable];
}

NSObject *objc = [[NSObject alloc] init];
[_hashTable addObject:objc];

NSLog(@"添加之后的 hashTable :%@", _hashTable);
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}


@end

打印结果:

1
2
3
4
5
6
2018-07-12 21:32:42.401083+0800 HashTableAndMapDemo[73674:2559037] 添加之后的 hashTable :NSHashTable {
[4] <NSObject: 0x60000001f9f0>
}

2018-07-12 21:32:42.401264+0800 HashTableAndMapDemo[73674:2559037] 调用之后的 hashTable:NSHashTable {
}

我们可以看到,在出了作用域之后,obj 立刻被释放了。集合里的引用也被安全的删除了。

NSMapTable

NSMapTable 对象类似与 NSDictionary 的数据结构,但是 NSMapTable 功能比 NSDictionary 对象要多的功能就是可以设置 keyvalueNSPointerFunctionsOptions 特性,其他的用法与 NSDictionary 相同。

特性

1. NSDictionary/NSMutableDictionary 会复制 keys 并且通过强引用 values 来实现存储。
2. NSMapTable 是可变的。
3. NSMapTable 可以通过弱引用来持有 keys 和 values,所以当 key 或者 value 被deallocated 的时候,所存储的实体也会被移除。
4. NSMapTable 可以在添加 value 的时候对 value 进行复制。

和 NSHashTable 类似,NSMapTable 可以随意的存储指针,并且利用指针的唯一性来进行对比和重复检查。

简单示例

来看看简单的示例:

1
2
3
4
5
6
7
8
9
10
11
12
- (void)testMap {
if (!_mapTable) {
_mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableStrongMemory];

NSObject *objc = [[NSObject alloc] init];
[_mapTable setObject:objc forKey:@"123"];

NSLog(@"keys: %@", [[_mapTable keyEnumerator] allObjects]);
NSLog(@"_map: %@", _mapTable);
}

}

打断点调试,断点1 放在 set 位置,断点2 放在 NSLog 位置:

1
2
3
4
5
6
7
(lldb) po CFGetRetainCount((__bridge  CFTypeRef)(objc));
1

(lldb) po CFGetRetainCount((__bridge CFTypeRef)(objc));
2

(lldb)

可以看到当 value 使用 NSMapTableStrongMemory 修饰时,objc 的引用计数为2.

1
2
3
4
5
6
7
(lldb) po CFGetRetainCount((__bridge  CFTypeRef)(objc));
1

(lldb) po CFGetRetainCount((__bridge CFTypeRef)(objc));
1

(lldb)

当 value 使用 NSMapTableWeakMemory 修饰时, objc 的引用计数为1.

可以看得出来,类似于 NSHashTable 选择,不同的模式,对于对象的引用持有是不同的。

结语

以上就是关于 NSHashTable 和 NSMapTable 相关的一些记载,其实,在开中 NSSet 和 NSDictionary 能解决大多数的问题,当然了解更多的知识点,对于自己的思路也是扩展的。所以,想了解更多的内容可以参考 这篇文章 以及 这篇文章,或者去问度娘。

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2020 KNOWLEDGE IS POWER All Rights Reserved.

访客数 : | 访问量 :