稍微研究了些NSArray,查找了各种资料,为了总结方便后续修改查找,记录如下:
0.系统Array分类

代码如下:

看名字也很好理解,
__NSPlaceholderArray: 占位的Array, 还未初始化
__NSSingleObjectArrayI: 只有一个元素的不可变Array
__NSArrayM: 可变Array
__NSArrayI: 不可变Array
__NSArray0: 0个元素的Array
1.内存布局
NSArray


第一个8字节是isa的信息,表明这个内存是__NSArrayI类型,第二个8字节是数组的长度,后面分别为各个元素的内存地址,说明对NSArray来说,它是个连续存储空间,存储了对象地址,至于对象在哪里就不是数组能管的了。对于不可变数组,如果直接找到其中元素的地址,来改变其中的值会不会打破不可变数组的定义。下节会讲。
NSMutableArray


同其他OC对象一样,内存的第一个8自己表示的是isa信息。NSMutableArray内存的第二个8字节恒为0,第三个8字节其实是元素的内存表,如下图所示

从0x283fb7780开始的三个8字节地址表示NSMutableArray的三个元素的地址,在上面的上面的图里面已经展开显示了。
扩展一下


我们在尾部加了两个元素,在头部insert了一个元素。
从内存对比图中可看出,第四个8字节中,前4个字节从00 --> 09,后4个字节从04-->A0(10).
猜测一下,A0表示分配出来的内存空间,至于为啥元素只增加到7个,却分配到了10个空间,我想是跟内存对齐有一些关系,沿着这个思路,前面的09就表示第一个元素的位置了,也就是offset。
那可以大胆猜测NSMutableArray的内存模型是一个两端可扩展的循环数使用的连续内存。
第五个字节的前4个字节是啥实在猜不出来,有知道的麻烦指导下,谢谢,后4个字节是数组的长度。


给这组图验证一下。
2.对象持有

走到26行,arr有4个元素,从内存地址可以看出,arr的元素的内存地址就是a,b,c,d变量的内存地址,但是这些变量是可变的。就像上节说的,如果找到元素的内存地址直接改变其内存只是否就改变了不可变数组了?这种想法太naive,马上被打脸.

改变a的值后,arr里持有的元素内存和值都没有改变,反而a的值和内存都改变了。
这估计就是编译器干的活吧,给使用者便利,真实的逻辑却大不相同。
3.增删操作




执行完了空间的变化是,增加的就增加在可变区域的后面,头部删除的就还存在那里,只是改变了上文说的offset,我们看看从中间删除会怎么处理?



做了收尾的增删后,增加的在后面,删除的头部元素也还在。只是offset变了。有个变化是内存地址从 0x600002479ec0 变到0x60000074c050, 说明是重新分配空间了。

中间删除元素后,我们发现前面的元素位置没变,从删除位起后面元素前移了,说明删除操作只是做数据移动。,而且内存地址还是0x60000074c050,我们试下删除前面的元素看:



删除了index为1的元素。从内存地址0x60000074c050没变,可以看到是将index 0的元素移动到index 1上了。
4.NSCopying协议


从copy后的类型都为__NSArrayI可以看出,copy操作出来的是不可变数组,不管对NSMutableArray还是NSArray,也不管赋值给可变数组还是不可变数组。
从内存地址上看,对NSArray不可变数组copy,内存地址是一样的,说明不可变数组copy,只是copy了指针。而对NSMutableArray可变数组进行copy操作就重新分配内存了。因为他将可变的转换为不可变的。
5.NSMutableCopying协议


mutableCopy操作就简单了,也从两方面看
1.不管对NSArray还是NSMutableArray进行mutableCopy操作,得到的都是MutableArray
2.不管对NSArray还是NSMutableArray进行mutableCopy操作,从内存上看,都是重新分配了内存。
以上一点总结,欢迎大家交流,请大神们不吝赐教。
网友评论