我对bbum在此问题上的答案持不同意见。 NSPointerArray
是一个数组,而不是稀疏数组,两者之间存在重要的区别。
我强烈建议不使用bbum所提供的解决方案。
NSPointerArray
的文档在这里可用。
Cocoa已经有了由NSArray
类定义的数组对象。NSPointerArray
继承自NSObject
,因此它不是NSArray
的直接子类。但是,NSPointerArray
的文档定义了该类如下:
NSPointerArray是一个可变集合,模拟了NSArray,但也可以容纳NULL值。
我将做出公理性假设,即文档中的这个定义断言了这是NSArray
的“逻辑”子类。
定义-
"一般"数组是:一个项目集合,每个项目都有一个与之相关联的唯一索引号。
数组(Array),简单来说是指索引按照以下属性排列的“通用”数组:数组中的项目索引从0
开始逐个增加。数组中的所有项目都包含一个小于数组项数的索引编号。向数组添加项必须在数组中最后一项的索引+1处,或者可以在两个现有项目索引号之间插入一个项目,导致所有随后的项目索引号递增1。可以用另一个项目替换已存在索引号的项目,此操作不会更改现有操作的索引编号。因此,插入和替换是两个不同的操作。
稀疏数组是指索引号的第一项可以从任何数字开始,而添加到该数组的后续项的索引号与数组中其他项无关或没有限制的“通用”数组。在稀疏数组中插入项目不会影响数组中其他项目的索引编号。在大多数实现中,插入项目和替换项目通常是同义词。稀疏数组中项目数量的计数与其索引编号没有关系。
这些定义对于一个可测试的“黑盒子”数组的行为做出了一些预测。为简单起见,我们将重点关注以下关系:
在一个数组中,所有项目的索引号都小于数组中项目的数量。尽管这对于稀疏数组可能是正确的,但它并不是一个要求。
在对bbum的评论中,我如下所述:
NSPointerArray
不是一个稀疏数组,也不像稀疏数组那样运作。您仍然需要用NULL
指针填充所有未使用的索引。在一个刚实例化的NSPointerArray
上执行[pointerArray insertPointer:@"test" atIndex:17];
的输出结果:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSConcretePointerArray insertPointer:atIndex:]: attempt to insert pointer at index 17 beyond bounds 0'
声明一下,没有证明,NSPointerArray
的行为违反了稀疏数组的定义。错误信息的这部分很有启示性:attempt to insert pointer at index 17 beyond bounds 0'
,特别是关于必须在索引0
处添加第一个新项的部分。
bbum随后发表评论:
那是不正确的。您未调用-setCount:将容量设置为足够的大小。
“设置计数”稀疏数组中项目数量的做法是荒谬的。如果NSPointerArray
是一个稀疏数组,那么在索引17处添加第一项后,预期NSPointerArray
中项目数量为1。然而,遵循bbum的建议,在添加第一项后,NSPointerArray
中的项目数量为18
,而不是1
。
QED-已经证明NSPointerArray
实际上是一个数组,并且在本讨论中是一个NSArray
。
此外,bbum发表了以下额外的评论:
NSPointerArray确实支持空洞。
这是可以证明为假的。一个数组要求其中包含的所有项目都包含某些内容,即使那个东西是“nothing”。这在稀疏数组中不成立。对于本讨论的目的,这就是“空洞”的确切定义。NSPointerArray在稀疏数组意义上不包含空洞。
那是编写该类的全部重点之一。你必须先设置计数。
对于稀疏数组,“设置计数”是无意义的。
内部实现是稀疏数组还是哈希表等是实现细节。
这是正确的。但是,NSPointerArray的文档没有提到它如何实现或管理其项目数组。此外,它没有在任何地方声明NSPointerArray“高效地管理空指针数组”。
QED- bbum依赖于NSPointerArray
通过内部的稀疏数组有效地处理NULL
指针的未记录行为。由于这是未记录行为,因此此行为随时可能更改,或者甚至可能不适用于NSPointerArray
的所有用途。如果存储在其中的最高索引号足够大(〜2^26),则此行为的更改将是灾难性的。
实际上,它并没有实现为一个大块内存...
同样,这是一个私有实现细节,是未记录的。依赖于这种类型的行为是极其糟糕的编程实践。
NSPointerArray
并不是一个稀疏数组,也没有相应的行为。你仍然需要用NULL
指针填充所有未使用的索引。在新创建的NSPointerArray
上执行[pointerArray insertPointer:@"test" atIndex:17];
操作的输出结果是:*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSConcretePointerArray insertPointer:atIndex:]: attempt to insert pointer at index 17 beyond bounds 0'
。 - johneNSPointerArray
自 iOS 6.0 起可用。 - james_womackNSPointerArray
并不是内存高效的,但这并不意味着它不是稀疏的。 - bbum