NSArray在内存中的数据结构(上)

所有观点是本人个人测试与推断,不能完全代表实际。

为方便读者,结论部分已加粗,源码在结尾给出。

笔者经常听别人说NSArray是顺序表结构,或者通过反编译插件打开NSArray的源码。但是笔者本身并不会用相应的插件,所以想用代码的方式探寻一下NSArray的数据结构。

NSArray

本人按照NSArray是顺序表来推测,做了以下工作:


测试函数

笔者的方法是,根据array的指针,通过C指针位移方法,查找array所有的存储单位,根据所存的内容与log区数组存储对象的地址比对,找到对象在array中的位置。

根据上述思路和代码,可得结果。


结果1


结果2

由此笔者推断,array确实是顺序表,array第二个存储单元存储的是count,第3-(count+2)个存储单元存储对应对象。且根据不管array建立多少个,他的第一个存储单元恒相同,推断与isa指针有关

至于总申请空间大小笔者还不知道如何计算。

NSSet


set测试


内存数据

set的数据结构跟Array大差不差,只不过最后一个元素40e8不见了,到了0x0000000282f3c310的位置,由此推测,set应该也是一个顺序表,但他不是顺序表的普通结构,set[2]与set[3]之间隔了两个存储空间,两个存储空间存储均为空应该会在搜索时跳过,但他一定不是一个链表,因为他没有链。

第一个存储空间存放的数据

笔者又做了关于第一个存储空间的测试

测试第一个存储空间内容

发现第一个存储空间的数据笔者没有能力作为地址解析。但是发现所有数组或集合的第一存储空间内容按类相同,于是根据对比isa指针与第一存储内容关系的比较得到以下推论:

第一个存储空间存储得并不是指针,而是按位存储的内容,一共八个字节是64位,前28位为固定值(000021a)可能与版本等固有信息有关,后36位的值减去1得到本类的isa指针。以isa指针来关联方法。

以下给出源码

//初始化一个数组拿到OC指针型

    NSArray *array=@[@"1",@"12",@"123",@"1234"];

    NSSet*set=[NSSetsetWithArray:array];


    //将这个数组指针转换为C指针,这样就可以用C方法进行内存位移访问

    char *p=(__bridge_retained void*)array;


    //因为OC地址是8个字节,这里推断OC数组也是8个字节作为一个元素存储空间;

    intlenght=8;

    //进行一次按存储空间的遍历这里预留了四个空间的长度,因为笔者担心OC数组并不是C数组,可能有加料,所以设长一点;

    for(inti=0; i<(array.count+4)*lenght; i+=lenght) {

        //初始化字符串作为容器来拼接存储内容。

        NSMutableString *mString=[NSMutableString string];

        //这里要按存储空间的每个字节取值,这里为什么用倒序,因为appending函数是往后拼接,所以高位开始,其实正序从低位拼接也不影响

        for(intj=7;j>=0;j--){

            //这里十六进制取两位已经足够一字节的数据了,针对数据出现ffffff的情况进行处理

            NSString*str=[NSStringstringWithFormat:@"%02x",*(p+i+j)];

            str = [strsubstringFromIndex:str.length-2];

            [mStringappendFormat:@"%@",str];

        }

        NSLog(@"数组第%d个单元读到的数据是:%@",i/lenght,mString);

    }

    ClassarrayClass=object_getClass(array);

    NSLog(@"%p,%@",arrayClass,arrayClass);



以上便是笔者的初步结论。后续会更新可变数组与集合。如有错漏,不吝指正。感谢。

你可能感兴趣的:(NSArray在内存中的数据结构(上))