【Objective-C基础】集合类

基础集合类是每一个Mac/iOS应用的基本组成部分。1

    NSArray/NSMutableArray
    NSSet/NSMutableSet/NSCountedSet
    NSOrderedSet/NSMutableOrderedSet
    NSIndexSet/NSMutableIndexSet
    NSDictionary/NSMutableDictionary

    NSPointerArray
    NSHashTable
    NSMapTable

可变性

大多数的集合类存在两个版本:可变和不可变(默认)。

最大的好处是什么?线程安全。不可变的集合完全是线程安全的,可以同时在多个线程中迭代,避免各种转变时出现异常的风险。你的 API 绝不应该暴露一个可变的集合。

当然从不可变到可变然后再回来是会有一定代价的 — 对象必须被拷贝两次,所有集合内的对象将被 retain/release。有时在内部使用一个可变的集合,而在访问时返回一个不可变的对象副本会更高效。

与其他框架不同的是,苹果没有提供一个线程安全的可变集合,NSCache 是例外,但它真的算不上是集合类,因为它不是一个通用的容器。大多数时候,你不会需要在集合层级的同步特性。想象一段代码,作用是检查字典中一个 key 是否存在,并根据检查结果决定设置一个新的 key 或者返回某些值 — 你通常需要把多个操作归类,这时线程安全的可变集合并不能对你有所帮助。

其实也有一些同步的,线程安全的可以使用的可变集合案例,它们往往只需要用几行代码,通过子类和组合的方法建立,比如这个 NSDictionary 或这个 NSArray。

需要注意的是,一些较新的集合类,如 NSHashTable,NSMapTable 和 NSPointerArray 默认就是可变的,它们并没有对应的不可变的类。它们用于类的内部使用,你基本应该不会能找到需要它们的不可变版本的应用场景。

NSArray/NSMutableArray

基于存储对象的多少,它使用各种内部的变体。最有趣的部分是苹果对于个别的对象访问并不保证 O(1) 的访问时间。    

NSDictionary/NSMutableDictionary

一个字典存储任意的对象键值对。

NSDictionary 中的键是被拷贝的并且需要是不变的。

跟数组相似的,字典根据尺寸的不同使用不同的实现,并在其中无缝切换。

一个有趣的细节是,在 NSDictionary 中键是被 copy 的,但是在使用一个 toll-free 桥接的 CFDictionary 时却只会被 retain。CoreFoundation 类没有通用的拷贝对象的方法,因此这时拷贝是不可能的(*)。这只适用于你使用 CFDictionarySetValue() 的时候。如果你是通过 setObject:forKey 来使用一个 toll-free 桥接的 CFDictionary 的话,苹果会为其增加额外处理逻辑,使得键被拷贝。但是反过来这个结论则不成立 — 使用已经转换为 CFDictionary 的 NSDictionary 对象,并用对其使用 CFDictionarySetValue() 方法,还是会导致调用回 setObject:forKey 并对键进行拷贝。

NSSet/NSMutableSet/NSCountedSet

OC中的集合(NSSet)与数学中的集合一样,集合中的元素具有唯一性、存储单元的元素是无序的、存储元素必须是对象类型。

OC中用Set表示集合,分为NSSet/NSMutableSet/NSCountedSet。NSSet对象的创建具有无序性,互异性。

NSCountedSet是NSMutableSet的子类,在NSMutableSet的基础上添加了计数功能,能记录元素的重复次数(方法为- [NSCountedSet countForObject:])。

NSSet的常用方法:

1、创建集合对象
2、获取元素个数
3、获取集合中的某个元素
4、判断集合中是否包含某个对象

NSOrderedSet/NSMutableOrderedSet

NSOrderedSet 在 iOS 5 和 Mac OS X 10.7 中第一次被引入,除了 Core Data,几乎没有直接使用它的 API。看上去它综合了 NSArray 和 NSSet 两者的好处,对象查找,对象唯一性,和快速随机访问。

NSOrderedSet解决了一个长期存在的烦恼(没有办法对一个关系集合做任意的排序),这是对使用Core Data的人来说极好的消息。从前,你不得不添加一个位置属性,当每次集合被修改时都要重新计算这个属性。没有一个内置的方法去验证你的位置集合是一个唯一的或者没有间隙的序列。

NSOrderedSet 有着优秀的 API 方法,使得它可以很便利的与其他 set 或者有序 set 对象合作。合并,交集,差集,就像 NSSet 支持的那样。它有 NSArray 中除了比较陈旧的基于函数的排序方法和二分查找以外的大多数排序方法。毕竟 containsObject: 非常快,所以没有必要再用二分查找了。

NSIndexSet/NSMutableIndexSet

有些使用场景下 NSIndexSet (和它的可变变体,NSMutableIndexSet) 真的非常出色,对它的使用贯穿在 Foundation 中。它可以用一种非常高效的方法存储一组无符号整数的集合,尤其是如果只是一个或少量范围的时候。正如 set 这个名字已经暗示的那样,每一个 NSUInteger 要么在索引 set 中,要么不在。如果你需要存储任意非唯一的数的时候,最好使用 NSArray。

NSDictionary/NSMutableDictionary

字典是用于保存具有映射关系数据的集合,它是存储key—value对的容器,一个key—value对认为是一个条目(entry),键值对在字典中是无序存储的。

与数组不同,字典靠key存取元素。key不能重复,value必须是对象。

字典分:不可变字典(NSDictionary)和可变字典(NSMutableDictionary)。不可变字典一旦创建,键值对就不可更改,不可添加,不可删除,仅能读取key或者value。

常用方法有:

1、创建字典对象
2、获取所有key值,获取所有value值
3、通过key值查询value

NSPointerArray

NSPointerArray类型是类似于NSArray的可变化版本,不同之处在于:

  • 可以持有nil值
  • 可以维持强引用/弱引用对象
  • 可以直接增加/减少count值。增加count值会插入NULL值。减少count
在性能方面,较之于 NSMutableArray , NSPointerArray 真的非常非常慢,所以当你打算在一个很大的数据集合上使用它的时候一定要三思。

NSHashTable

NSHashTable 效仿了 NSSet,但在对象/内存处理时更加的灵活。可以通过自定义 CFSet 的回调获得 NSHashTable 的一些特性,哈希表可以保持对对象的弱引用并在对象被销毁之后正确的将其移除,有时候如果手动在 NSSet 中添加的话,想做到这个是挺恶心的一件事。它是默认可变的 — 并且这个类没有相应的不可变版本。

NSHashTable 有 ObjC 和原始的 C API,C API 可以用来存储任意对象。苹果在 10.5 Leopard 系统中引入了这个类,但是 iOS 的话直到最近的 iOS 6 中才被加入。足够有趣的是它们只移植了 ObjC API;更多强大的 C API 没有包括在 iOS 中。

如果你只是需要 NSSet 的特性,请坚持使用 NSSet。
NSHashTable 在添加对象时花费了将近2倍的时间,但是其他方面的效率却非常相近。

NSMapTable

NSMapTable 和 NSHashTable 相似,但是效仿的是 NSDictionary。因此,我们可以通过 mapTableWithKeyOptions:valueOptions: 分别控制键和值的对象获取/保留行为。存储弱引用是 NSMapTable 最有用的特性,这里有4个方便的构造函数:

strongToStrongObjectsMapTable
weakToStrongObjectsMapTable
strongToWeakObjectsMapTable
weakToWeakObjectsMapTable

注意,除了使用 NSPointerFunctionsCopyIn,任何的默认行为都会 retain (或弱引用)键对象而不会拷贝它,这与 CFDictionary 的行为相同而与 NSDictionary 不同。当你需要一个字典,它的键没有实现 NSCopying 协议的时候(比如像 UIView),这会非常有用。

如果你好奇为什么苹果”忘记”为 NSMapTable 增加下标,你现在知道了。下标访问需要一个 id 作为 key,对 NSMapTable 来说这不是强制的。如果不通过一个非法的 API 协议或者移除 NSCopying 协议来削弱全局下标,是没有办法给它增加下标的。

你可以通过 dictionaryRepresentation 把内容转换为普通的 NSDictionary。不像 NSOrderedSet,这个方法返回的是一个常规的字典而不是一个代理。

NSMapTable 只比 NSDictionary 略微慢一点。
如果你需要一个不 retain 键的字典,放弃 CFDictionary 而使用它吧。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值