NSMutableArray
则不同。例如,在文档中指出(我强调):
那么,注:大多数数组操作都需要恒定时间:访问元素、在任一端添加或删除元素以及替换元素。将元素插入数组的中间位置需要线性时间。
NSMutableArray
到底是什么?这个有文档记录吗?NSMutableArray
则不同。例如,在文档中指出(我强调):
那么,注:大多数数组操作都需要恒定时间:访问元素、在任一端添加或删除元素以及替换元素。将元素插入数组的中间位置需要线性时间。
NSMutableArray
到底是什么?这个有文档记录吗?这是一个围绕着循环缓冲区的包装器。
这并没有文档记录也没有开源,但是这篇博客文章展示了令人惊叹的NSMutableArray
逆向工程,我认为你会非常感兴趣。
NSMutableArray
类簇由一个名为__NSArrayM
的具体私有子类支持。
最大的发现是NSMutableArray
不是像人们可能认为的那样对CFArray
进行简单封装:因为CFArray
是开源的,而且它不使用循环缓冲区,而__NSArrayM
则使用了循环缓冲区。
通过阅读文章评论,似乎从iOS 4开始就是这种方式了,而在之前的SDK中,NSMutableArray
实际上使用内部的CFArray
,并且甚至没有__NSArrayM
。
正如我上面提到的博客文章所述:
数据结构
正如你可能已经猜到的,
__NSArrayM
使用了循环缓冲区。 这种数据结构非常简单,但比普通数组/缓冲区稍微复杂一些。当到达任何一端时,循环缓冲区的内容都可以绕回。循环缓冲区具有一些非常酷的特性。特别地,除非缓冲区已满,否则从任一端插入/删除都不需要移动任何内存。
objectAtIndex:
的伪代码如下:
- (id)objectAtIndex:(NSUInteger)index {
if (_used <= index) {
goto ThrowException;
}
NSUInteger fetchOffset = _offset + index;
NSUInteger realOffset = fetchOffset - (_size > fetchOffset ? 0 : _size);
return _list[realOffset];
ThrowException:
// exception throwing code
}
其中 ivars 定义如下:
_used
: 数组中元素的数量_list
: 循环缓冲区的指针_size
: 缓冲区的大小_offset
: 数组在缓冲区中的第一个元素的索引再次声明,以上所有信息均来自 Bartosz Ciechanowski 的博客文章,本人不对其信息负责。
NSArray
和NSMutableArray
与CFArray
没有任何共同之处。 - Gabriele PetronellaCFArray
没有使用循环缓冲区。 - Gabriele PetronellaNSMutableArray
的两端插入和删除操作都可以在常数时间内完成,使其适用于作为队列使用。 - Gabriele PetronellaCFArray
是C数据结构,因此不能成为NSArray
的子类" - 这两者之间存在无缝桥接的原因。Objective-C对象和类本质上都是C结构体。至少这两种类型的“公共”部分布局是相同的。另外,尝试运行这个 - 我有NSMutableArray
,所以在我的Mac上,CFArray
实际上是NSMutableArray
的具体子类。这并不意味着它们的实现不能不同,但是请注意你的措辞。 - user3447428进行了一些测量:从一个空数组开始,添加了100,000次@"Hello",然后又删除了100,000次。不同的模式:在末尾、开头、中间、靠近开头(如果可能,在索引20处)和靠近结尾(如果可能,在距离结尾20个索引处),还有一种是在靠近开头和结尾之间交替进行。以下是100,000个对象的时间(在Core 2 Duo上测量):
Adding objects = 0.006593 seconds
Removing objects at the end = 0.004674 seconds
Adding objects at the start = 0.003577 seconds
Removing objects at the start = 0.002936 seconds
Adding objects in the middle = 3.057944 seconds
Removing objects in the middle = 3.059942 seconds
Adding objects close to the start = 0.010035 seconds
Removing objects close to the start = 0.007599 seconds
Adding objects close to the end = 0.008005 seconds
Removing objects close to the end = 0.008735 seconds
Adding objects close to the start / end = 0.008795 seconds
Removing objects close to the start / end = 0.008853 seconds
NSMutableArray
背后的数据结构是什么。循环缓冲区来自于实际实现的逆向工程,而不是开源代码(Foundation没有可用的开源代码),所以这里没有人做出那样的假设。 - Gabriele Petronella