【OC梳理】NSPointerArray、NSMapTable、NSHashTable

NSPointerArray、NSMapTable、NSHashTable是iOS 6.0之后新增的集合类型,对应于原来的NSArray、NSSet、NSDictionary。

NSPointerArray

NSPointerArray和NSArray/NSMutableArray一样,用于有序的插入或移除。不同的是:

  • 可以存储 nil,并且 nil 还参与 count 的计算。
  • count 值可以直接设置,如果直接设置count,那么会使用 nil 占位。
  • 可以使用 weak 来修饰元素,可以添加所有的指针类型。
  • 可以通过 for...in 来进行遍历。

也有一些缺点:

  • 操作均基于 index,无法通过 object 来进行操作;
  • 无法直接插入 array,或用 array 初始化;
  • 查找功能没有 NSArray 强大;
  • 没有逆序、排序等 API 提供

初始化

NSPointerArray 有两个初始化方法:

- (instancetype)initWithOptions:(NSPointerFunctionsOptions)options;
- (instancetype)initWithPointerFunctions:(NSPointerFunctions *)functions; 

+ (NSPointerArray *)pointerArrayWithOptions:(NSPointerFunctionsOptions)options;
+ (NSPointerArray *)pointerArrayWithPointerFunctions:(NSPointerFunctions *)functions;

NSPointerFunctionsOptions主要分为三大类:

内存管理

  • NSPointerFunctionsStrongMemory:缺省值,在 CG 和 MRC 下强引用成员
  • NSPointerFunctionsZeroingWeakMemory:已废弃,在 GC 下,弱引用指针,防止悬挂指针
  • NSPointerFunctionsMallocMemory 与 NSPointerFunctionsMachVirtualMemory:3 用于 Mach 的虚拟内存管理
  • NSPointerFunctionsWeakMemory:在 CG 或者 ARC 下,弱引用成员

特性,用于标明对象判等方式

  • NSPointerFunctionsObjectPersonality:hash、isEqual、对象描述
  • NSPointerFunctionsOpaquePersonality:pointer 的 hash 、直接判等
  • NSPointerFunctionsObjectPointerPersonality:pointer 的 hash、直接判等、对象描述
  • NSPointerFunctionsCStringPersonality:string 的 hash、strcmp 函数、UTF-8 编码方式的描述
  • NSPointerFunctionsStructPersonality:内存 hash、memcmp 函数
  • NSPointerFunctionsIntegerPersonality:值的 hash

内存标识

  • NSPointerFunctionsCopyIn:根据第二类的选择,来具体处理。

可以使用多个组合进行初始化:

NSPointerFunctionsOptions opt = NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality | NSPointerFunctionsCopyIn;
NSPointerArray *point = [[NSPointerArray alloc]initWithOptions:opt];

NSPointerFunctions
使用NSPointerFunctions可以自定义NSPointerArray对元素的处理方式:如何内存管理、如何hash、如何判断相等(isEqual)。
NSPointerFunctions初始化时可设置NSPointerFunctionsOptions

- (instancetype)initWithOptions:(NSPointerFunctionsOptions)options;
+ (NSPointerFunctions *)pointerFunctionsWithOptions:(NSPointerFunctionsOptions)options;

如果需要自定义实现函数,可以使用下面的对应属性:

// 自定义指针函数
// hash函数
@property (nullable) NSUInteger (*hashFunction)(const void *item, NSUInteger (* _Nullable size)(const void *item));
// isEqual函数
@property (nullable) BOOL (*isEqualFunction)(const void *item1, const void*item2, NSUInteger (* _Nullable size)(const void *item));
// size函数
@property (nullable) NSUInteger (*sizeFunction)(const void *item);
// 描述函数
@property (nullable) NSString * _Nullable (*descriptionFunction)(const void *item);

// 自定义内存配置
// 移除元素时的处理函数
@property (nullable) void (*relinquishFunction)(const void *item, NSUInteger (* _Nullable size)(const void *item));
// 添加元素时的处理函数
@property (nullable) void * _Nonnull (*acquireFunction)(const void *src, NSUInteger (* _Nullable size)(const void *item), BOOL shouldCopy);

可以自行实现函数,然后将函数指针赋给对应属性即可,比如,isEqual:

static BOOL IsEqual(const void *item1, const void *item2, NSUInteger (*size)(const void *item)) {
    return *(const int *)item1 == *(const int *)item2;
}

NSPointerFunctions *functions = [[NSPointerFunctions alloc] init];
[functions setIsEqualFunction:IsEqual]; 

操作数组

添加元素:

- (void)addPointer:(nullable void *)pointer;

移除元素:

- (void)removePointerAtIndex:(NSUInteger)index; 

插入元素:

- (void)insertPointer:(nullable void *)item atIndex:(NSUInteger)index;

替换元素:

- (void)replacePointerAtIndex:(NSUInteger)index withPointer:(nullable void *)item;

如果想实现类似Array的根据下标赋值,可以为它添加一个分类:


@interface NSPointerArray(Set)

/// 设置目标位置的值
- (void)setObject:(id)anObject
          atIndex:(NSUInteger)idx;

@end

@implementation NSPointerArray(Set)

- (void)setObject:(id)anObject
          atIndex:(NSUInteger)idx{
    if (self.count > idx) {
       self.count = idx + 2;
    }
    [self insertPointer:(__bridge void * _Nullable)(anObject) atIndex:idx];
}

@end

NSMapTable

与 NSMapTable 对应的,是 NSMutableDictionary。除了 集合的共有特点以外,比起传统字典,它还有一些优势:

  • key 可以不用遵循 NSCopying 协议;
  • key 和 value 的内存管理方式可以分开,如:key 是强引用,value 是弱引用;

相比起 NSPointerArray,NSMapTable 的初始化方法要多得多:

// 虽然有 capacity 参数,但实际没用到
- (instancetype)initWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions capacity:(NSUInteger)initialCapacity;
- (instancetype)initWithKeyPointerFunctions:(NSPointerFunctions *)keyFunctions valuePointerFunctions:(NSPointerFunctions *)valueFunctions capacity:(NSUInteger)initialCapacity;
 
+ (NSMapTable<KeyType, ObjectType> *)mapTableWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions;
 
// 返回指定 key、value 内存管理类型的 map
+ (NSMapTable<KeyType, ObjectType> *)strongToStrongObjectsMapTable NS_AVAILABLE(10_8, 6_0);
+ (NSMapTable<KeyType, ObjectType> *)weakToStrongObjectsMapTable NS_AVAILABLE(10_8, 6_0);
+ (NSMapTable<KeyType, ObjectType> *)strongToWeakObjectsMapTable NS_AVAILABLE(10_8, 6_0);
+ (NSMapTable<KeyType, ObjectType> *)weakToWeakObjectsMapTable NS_AVAILABLE(10_8, 6_0);

其实,这么多的初始化方法就对应着四种搭配:

  • key 为 strong,value 为 strong
  • key 为 strong,value 为 weak
  • key 为 weak,value 为 strong
  • key 为 weak,value 为 weak

当用 weak 修饰 key 或 value 时,有一方被释放,则该键值对移除。

NSHashTable

NSHashTable 对应 NSMutableSet,它的 API 更为简单,与 NSMapTable 同样,初始化方法的 capacity 并未生效。

- (instancetype)initWithOptions:(NSPointerFunctionsOptions)options capacity:(NSUInteger)initialCapacity;
- (instancetype)initWithPointerFunctions:(NSPointerFunctions *)functions capacity:(NSUInteger)initialCapacity;

值得注意的是,NSHashTable 有一个 allObjectes 的属性,返回 NSArray,即使 NSHashTable 是弱引用成员,allObjects 依然会对成员进行强引用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 142,461评论 1 300
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 61,089评论 1 256
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 94,078评论 0 212
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 40,938评论 0 175
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 48,698评论 1 255
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 38,733评论 1 175
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 30,340评论 2 268
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,138评论 0 165
  • 想象着我的养父在大火中拼命挣扎,窒息,最后皮肤化为焦炭。我心中就已经是抑制不住地欢快,这就叫做以其人之道,还治其人...
    爱写小说的胖达阅读 28,949评论 6 229
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 32,493评论 0 213
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,269评论 2 214
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 30,591评论 1 229
  • 白月光回国,霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前, 不然我有一百种方法让你生不如死。]我...
    爱写小说的胖达阅读 24,216评论 0 31
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,107评论 2 213
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 31,485评论 3 204
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,615评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,006评论 0 167
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 33,496评论 2 230
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 33,572评论 2 230

推荐阅读更多精彩内容